home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Utilities / Datatypes / AnimDT / dispatch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-25  |  129.2 KB  |  3,966 lines

  1.  
  2. /*
  3. **
  4. **  $VER: dispatch.c 1.11 (25.9.97)
  5. **  anim.datatype 1.11
  6. **
  7. **  Dispatch routine for a DataTypes class
  8. **
  9. **  Written 1996/1997 by Roland 'Gizzy' Mainz
  10. **  Original example source from David N. Junod
  11. **
  12. */
  13.  
  14. /* Use asyncronous I/O below. Disabled due problems with Seek'ing */
  15. #if 0
  16. #define DOASYNCIO 1
  17. #endif
  18.  
  19. #if 0
  20. #define D( x ) x
  21. #else
  22. #define D( x )
  23. #endif
  24.  
  25. /* main includes */
  26. #include "classbase.h"
  27. #include "classdata.h"
  28. #include "asyncio.h"
  29.  
  30. /*****************************************************************************/
  31.  
  32. /* IFF errors to DOS errors */
  33. static const
  34. LONG ifferr2doserr[] =
  35. {
  36.   0L,                         /* End of file (not an error).                  */
  37.   0L,                         /* End of context (not an error).               */
  38.   DTERROR_INVALID_DATA,       /* No lexical scope.                            */
  39.   ERROR_NO_FREE_STORE,        /* Insufficient memory.                         */
  40.   ERROR_SEEK_ERROR,           /* Stream read error.                           */
  41.   ERROR_SEEK_ERROR,           /* Stream write error.                          */
  42.   ERROR_SEEK_ERROR,           /* Stream seek error.                           */
  43.   DTERROR_INVALID_DATA,       /* File is corrupt.                             */
  44.   DTERROR_INVALID_DATA,       /* IFF syntax error.                            */
  45.   ERROR_OBJECT_WRONG_TYPE,    /* Not an IFF file.                             */
  46.   ERROR_REQUIRED_ARG_MISSING, /* Required call-back hook missing.             */
  47.   0xDEADDEADUL                /* Return to client.  You should never see this */
  48. };
  49.  
  50. /*****************************************************************************/
  51.  
  52. /* local prototypes */
  53. static                 BOOL                 FreeAbleFrame( struct AnimInstData *, struct FrameNode * );
  54. static                 STRPTR               GetPrefsVar( struct ClassBase *, STRPTR );
  55. static                 void                 YouShouldRegister( struct ClassBase *, struct AnimInstData * );
  56. static                 BOOL                 matchstr( struct ClassBase *, STRPTR, STRPTR );
  57. static                 void                 ReadENVPrefs( struct ClassBase *, struct AnimInstData * );
  58. static                 LONG                 LoadFrames( struct ClassBase *, Object * );
  59. static                 struct FrameNode    *AllocFrameNode( struct ClassBase *, APTR );
  60. static                 struct FrameNode    *FindFrameNode( struct MinList *, ULONG );
  61. static                 void                 FreeFrameNodeResources( struct ClassBase *, struct MinList * );
  62. static                 void                 CopyBitMap( struct ClassBase *, struct BitMap *, struct BitMap * );
  63. static                 void                 XCopyMem( struct ClassBase *, APTR, APTR, ULONG );
  64. static                 void                 ClearBitMap( struct BitMap * );
  65. static                 void                 XORBitMaps( struct BitMap *, struct BitMap * );
  66. static                 struct BitMap       *AllocBitMapPooled( struct ClassBase *, ULONG, ULONG, ULONG, APTR );
  67. static                 BOOL                 CMAP2Object( struct ClassBase *, Object *, UBYTE *, ULONG );
  68. static                 struct ColorMap     *CMAP2ColorMap( struct ClassBase *, struct AnimInstData *, UBYTE *, ULONG );
  69. static                 struct ColorMap     *CopyColorMap( struct ClassBase *, struct ColorMap * );
  70. static                 APTR                 AllocVecPooled( struct ClassBase *, APTR, ULONG );
  71. static                 void                 FreeVecPooled( struct ClassBase *, APTR, APTR );
  72. static                 LONG                 DrawDLTA( struct ClassBase *, struct AnimInstData *, struct BitMap *, struct BitMap *, struct AnimHeader *, UBYTE *, ULONG );
  73. static                 void                 DumpAnimHeader( struct ClassBase *, struct AnimInstData *, ULONG, struct AnimHeader * );
  74. static                 struct FrameNode    *GetPrevFrameNode( struct FrameNode *, ULONG );
  75. static                 void                 OpenLogfile( struct ClassBase *, struct AnimInstData * );
  76. static                 void                 mysprintf( struct ClassBase *, STRPTR, STRPTR, ... );
  77. static                 void                 verbose_printf( struct ClassBase *, struct AnimInstData *, STRPTR, ... );
  78. static                 void                 error_printf( struct ClassBase *, struct AnimInstData *, STRPTR, ... );
  79. static                 void                 AttachSample( struct ClassBase *, struct AnimInstData * );
  80.  
  81. static                 ULONG                SaveIFFAnim( struct ClassBase *, struct IClass *, Object *, struct dtWrite * );
  82. static                 struct IFFHandle    *CreateDOSIFFHandle( struct ClassBase *, BPTR );
  83. static                 LONG                 StartIFFAnim3( struct ClassBase *, struct AnimInstData *, struct IFFHandle *iff, struct AnimContext *, struct BitMapHeader *, ULONG, ULONG *, ULONG, ULONG, ULONG, struct BitMap * );
  84. static                 void                 EndIFFAnim3( struct ClassBase *, struct AnimInstData *, struct IFFHandle * );
  85. static                 LONG                 WriteIFFAnim3( struct ClassBase *, struct IFFHandle *, struct AnimContext *, ULONG, ULONG, struct BitMapHeader *, ULONG *, ULONG, struct BitMap * );
  86. static                 LONG                 PutAnim3Delta( struct ClassBase *, struct IFFHandle *, struct AnimContext *, struct BitMap *, struct BitMap * );
  87. static                 LONG                 PutILBMCMAP( struct ClassBase *, struct IFFHandle *, ULONG *, ULONG );
  88. static                 LONG                 PutILBMBody( struct ClassBase *, struct IFFHandle *, struct BitMap *, struct BitMapHeader * );
  89. static                 struct AnimContext  *CreateAnimContext( struct ClassBase *, ULONG, ULONG, ULONG );
  90. #if 0
  91. static                 struct BitMap       *PrevFrame( struct ClassBase *, struct AnimContext * );
  92. #endif
  93. static                 void                 SwapFrames( struct ClassBase *, struct AnimContext * );
  94. static                 struct BitMap       *CurrFrame( struct ClassBase *, struct AnimContext * );
  95. static                 void                 DeleteAnimContext( struct ClassBase *, struct AnimContext * );
  96.  
  97.  
  98. /*****************************************************************************/
  99.  
  100. /* Create "anim.datatype" BOOPSI class */
  101. struct IClass *initClass( struct ClassBase *cb )
  102. {
  103.     struct IClass *cl;
  104.  
  105.     /* Create our class... */
  106.     if( cl = MakeClass( ANIMDTCLASS, ANIMATIONDTCLASS, NULL, (ULONG)sizeof( struct AnimInstData ), 0UL ) )
  107.     {
  108.       cl -> cl_Dispatcher . h_Entry = (HOOKFUNC)Dispatch;
  109.       cl -> cl_UserData             = (ULONG)cb;
  110.  
  111.       AddClass( cl );
  112.     }
  113.  
  114.     return( cl );
  115. }
  116.  
  117. /*****************************************************************************/
  118.  
  119. struct MyStackSwapStruct
  120. {
  121.     struct StackSwapStruct  stk;
  122.     struct IClass          *cl;
  123.     Object                 *o;
  124.     Msg                     msg;
  125. };
  126.  
  127. /*****************************************************************************/
  128.  
  129.  
  130. DISPATCHERFLAGS
  131. ULONG Dispatch( REGA0 struct IClass *cl, REGA2 Object *o, REGA1 Msg msg )
  132. {
  133.     struct ClassBase         *cb = (struct ClassBase *)(cl -> cl_UserData);
  134.     ULONG                     retval;
  135.     struct MyStackSwapStruct  mystk;
  136.     UBYTE                    *lower,
  137.                              *upper,
  138.                              *sp;
  139.     struct Task              *ThisTask;
  140.     ULONG                     stacksize;
  141.  
  142.     mystk . cl                = cl;
  143.     mystk . o                 = o;
  144.     mystk . msg               = msg;
  145.  
  146.     ThisTask = FindTask( NULL );
  147.     stacksize = (ULONG)(((UBYTE *)(ThisTask -> tc_SPReg)) - ((UBYTE *)(ThisTask -> tc_SPLower)));
  148.  
  149. #define DTSTACKSIZE (16384UL)
  150.  
  151.     /* Enougth stack ? */
  152.     if( stacksize > (DTSTACKSIZE / 2UL) )
  153.     {
  154.       retval = MyDispatch( (&mystk) );
  155.     }
  156.     else
  157.     {
  158.       /* Alloc a new stack frame... */
  159.       while( !(lower = (UBYTE *)AllocMem( DTSTACKSIZE, MEMF_PUBLIC )) );
  160.  
  161.       sp = upper = lower + DTSTACKSIZE;
  162.  
  163.       mystk . stk . stk_Lower   = lower;
  164.       mystk . stk . stk_Upper   = (ULONG)upper;
  165.       mystk . stk . stk_Pointer = sp;
  166.  
  167.       retval = SwapMe( (&mystk) );
  168.  
  169.       FreeMem( lower, DTSTACKSIZE );
  170.     }
  171.  
  172.     return( retval );
  173. }
  174.  
  175.  
  176. DISPATCHERFLAGS
  177. ULONG SwapMe( REGA0 struct MyStackSwapStruct *mystk )
  178. {
  179.     register ULONG retval;
  180.  
  181. #define cb ((struct ClassBase *)(mystk -> cl -> cl_UserData))
  182.  
  183.     StackSwap( (&(mystk -> stk)) );
  184.  
  185.       retval = MyDispatch( mystk );
  186.  
  187.     StackSwap( (&(mystk -> stk)) );
  188.  
  189. #undef cb
  190.  
  191.     return( retval );
  192. }
  193.  
  194.  
  195. /* class dispatcher */
  196. DISPATCHERFLAGS
  197. ULONG MyDispatch( REGA0 struct MyStackSwapStruct *mystk )
  198. {
  199.     struct IClass        *cl  = mystk -> cl;
  200.     Object               *o   = mystk -> o;
  201.     Msg                   msg = mystk -> msg;
  202.     struct ClassBase     *cb = (struct ClassBase *)(cl -> cl_UserData);
  203.     struct AnimInstData  *aid;
  204.     ULONG                 retval = 0UL;
  205.  
  206.     switch( msg -> MethodID )
  207.     {
  208. /****** anim.datatype/OM_NEW *************************************************
  209. *
  210. *    NAME
  211. *        OM_NEW -- Create a anim.datatype object.
  212. *
  213. *    FUNCTION
  214. *        The OM_NEW method is used to create an instance of the anim.datatype
  215. *        class.  This method is passed to the superclass first. After this,
  216. *        anim.datatype parses the prefs file and makes a scan through
  217. *        the data to get index information. Frame bitmaps are loaded if the
  218. *        input stream isn't seekable (e.g. IFF handle/clipboard),
  219. *        colormaps and the first frame are loaded immediately.
  220. *        If a sample was set in the prefs, it will be loaded and attached
  221. *        to the animation.
  222. *
  223. *    ATTRIBUTES
  224. *        The following attributes can be specified at creation time.
  225. *
  226. *        DTA_SourceType (ULONG) -- Determinates the type of DTA_Handle
  227. *            attribute. DTST_FILE, DTST_CLIPBOARD and DTST_RAM are supported.
  228. *            If any other type was set in a given DTA_SourceType,
  229. *            OM_NEW will be rejected.
  230. *            A sourcetype of DTST_CLIPBOARD forces the LOADALL prefs
  231. *            switch (can't seek on clipboard).
  232. *            Defaults to DTST_FILE.
  233. *
  234. *        DTA_Handle -- For both DTST_FILE and DTST_CLIPBOARD, a
  235. *            (struct IFFHandle *) is expected. This handle will be
  236. *            created by datatypesclass depeding on the DTF_#? flag, which
  237. *            is DTF_IFF here.  DTST_FILE, datatypesclass creates
  238. *            a IFF handle from the given DTA_Name and DTA_Handle (a
  239. *            BPTR returned by Lock), if DTST_CLIPBOARD, datatypesclass
  240. *            passes the given (IFF) handle through.
  241. *            A DTST_RAM (create empty object) source type requires a NULL
  242. *            handle.
  243. *
  244. *    RESULT
  245. *        If the object was created a pointer to the object is returned,
  246. *        otherwise NULL is returned.
  247. *
  248. ******************************************************************************
  249. *
  250. */
  251.       case OM_NEW:
  252.       {
  253.           struct TagItem *ti;
  254.  
  255.           /* We only support DTST_FILE, DTST_CLIPBOARD or DTST_RAM as source type */
  256.           if( ti = FindTagItem( DTA_SourceType, (((struct opSet *)msg) -> ops_AttrList) ) )
  257.           {
  258.             if( ((ti -> ti_Data) != DTST_FILE)      &&
  259.                 ((ti -> ti_Data) != DTST_CLIPBOARD) &&
  260.                 ((ti -> ti_Data) != DTST_RAM) )
  261.             {
  262.               SetIoErr( ERROR_OBJECT_WRONG_TYPE );
  263.  
  264.               break;
  265.             }
  266.           }
  267.  
  268.           /* Create object */
  269.           if( retval = DoSuperMethodA( cl, o, msg ) )
  270.           {
  271.             LONG error;
  272.  
  273.             /* Load frames... */
  274.             if( error = LoadFrames( cb, (Object *)retval ) )
  275.             {
  276.               /* Something went fatally wrong, dispose object */
  277.               CoerceMethod( cl, (Object *)retval, OM_DISPOSE );
  278.               retval = 0UL;
  279.             }
  280.  
  281.             SetIoErr( error );
  282.           }
  283.       }
  284.           break;
  285.  
  286. /****** anim.datatype/OM_DISPOSE *********************************************
  287. *
  288. *    NAME
  289. *        OM_DISPOSE -- Delete a anim.datatype object.
  290. *
  291. *    FUNCTION
  292. *        The OM_DISPOSE method is used to delete an instance of the
  293. *        anim.datatype class. This method is passed to the superclass when
  294. *        it has completed.
  295. *        This method frees all frame nodes and their contents (bitmaps,
  296. *        colormaps, samples etc.)
  297. *
  298. *    RESULT
  299. *        The object is deleted. 0UL is returned.
  300. *
  301. ******************************************************************************
  302. *
  303. */
  304.       case OM_DISPOSE:
  305.       {
  306.           /* Get a pointer to our object data */
  307.           aid = (struct AnimInstData *)INST_DATA( cl, o );
  308.  
  309.           /* Wait for any outstanding blitter usage (which may use one of our bitmaps) */
  310.           WaitBlit();
  311.  
  312.           /* Free colormaps etc. */
  313.           FreeFrameNodeResources( cb, (&(aid -> aid_FrameList)) );
  314.  
  315.           /* Free our key bitmap */
  316.           FreeBitMap( (aid -> aid_KeyBitMap) );
  317.  
  318.           /* Delete the pools */
  319.           DeletePool( (aid -> aid_FramePool) );
  320.           DeletePool( (aid -> aid_Pool) );
  321.  
  322.           /* Close input file */
  323.           if( aid -> aid_FH )
  324.           {
  325. #ifdef DOASYNCIO
  326.             CloseAsync( cb, (aid -> aid_FH) );
  327. #else
  328.             Close( (aid -> aid_FH) );
  329. #endif /* DOASYNCIO */
  330.           }
  331.  
  332.           /* Close verbose output file */
  333.           if( aid -> aid_VerboseOutput )
  334.           {
  335.             Close( (aid -> aid_VerboseOutput) );
  336.           }
  337.  
  338.           /* Dispose object */
  339.           DoSuperMethodA( cl, o, msg );
  340.       }
  341.           break;
  342.  
  343.       case OM_UPDATE:
  344.       {
  345.           if( DoMethod( o, ICM_CHECKLOOP ) )
  346.           {
  347.             break;
  348.           }
  349.       }
  350.       case OM_SET:
  351.       {
  352.           /* Pass the attributes to the animation class and force a refresh if we need it */
  353.           if( retval = DoSuperMethodA( cl, o, msg ) )
  354.           {
  355.             /* Top instance ? */
  356.             if( OCLASS( o ) == cl )
  357.             {
  358.               struct RastPort *rp;
  359.  
  360.               /* Get a pointer to the rastport */
  361.               if( rp = ObtainGIRPort( (((struct opSet *)msg) -> ops_GInfo) ) )
  362.               {
  363.                 struct gpRender gpr;
  364.  
  365.                 /* Force a redraw */
  366.                 gpr . MethodID   = GM_RENDER;
  367.                 gpr . gpr_GInfo  = ((struct opSet *)msg) -> ops_GInfo;
  368.                 gpr . gpr_RPort  = rp;
  369.                 gpr . gpr_Redraw = GREDRAW_UPDATE;
  370.  
  371.                 DoMethodA( o, (Msg)(&gpr) );
  372.  
  373.                 /* Release the temporary rastport */
  374.                 ReleaseGIRPort( rp );
  375.  
  376.                 retval = 0UL;
  377.               }
  378.             }
  379.           }
  380.       }
  381.           break;
  382.  
  383. /****** anim.datatype/DTM_WRITE **********************************************
  384. *
  385. *    NAME
  386. *        DTM_WRITE -- Save data
  387. *
  388. *    FUNCTION
  389. *        This method saves the object's contents to disk.
  390. *
  391. *        If dtw_Mode is DTWM_IFF, the method is passed unchanged to the
  392. *        superclass, animation.datatype, which writes a single IFF ILBM
  393. *        picture.
  394. *
  395. *        If dtw_mode is DTWM_RAW, the object saved an IFF ANIM stream to
  396. *        the filehandle given, starting with the current frame until
  397. *        the end is reached.
  398. *        The sequence saved can be controlled by the ADTA_Frame, ADTA_Frames
  399. *        and ADTA_FrameIncrement attributes (see TAGS section below).
  400. *
  401. *    TAGS
  402. *        When writing the local ("raw") format, IFF ANIM, the following
  403. *        attributes are recognized:
  404. *
  405. *        ADTA_Frame (ULONG) - start frame, saving starts here.
  406. *            Defaults to the current frame displayed.
  407. *
  408. *        ADTA_Frames (ULONG) - the number of frames to be saved,
  409. *            Defaults to (max_num_of_frames - curr_frame).
  410. *
  411. *        ADTA_FrameIncrement (ULONG) - frame increment when saving.
  412. *            Defaults to 1, which means: "jump to next frame".
  413. *
  414. *    NOTE
  415. *        - Any sound attached to the animation will NOT be saved.
  416. *
  417. *        - A CTRL-D signal to the writing process aborts the save.
  418. *
  419. *    RESULT
  420. *        Returns 0 for failure (IoErr() returns result2), non-zero
  421. *        for success.
  422. *
  423. ******************************************************************************
  424. *
  425. */
  426.       case DTM_WRITE:
  427.       {
  428.           struct dtWrite *dtw;
  429.  
  430.           dtw = (struct dtWrite *)msg;
  431.  
  432.           /* Local data format not supported yet... */
  433.           if( (dtw -> dtw_Mode) == DTWM_RAW )
  434.           {
  435.             retval = SaveIFFAnim( cb, cl, o, dtw );
  436.           }
  437.           else
  438.           {
  439.             /* Pass msg to superclass (which writes a single frame as an IFF ILBM picture)... */
  440.             retval = DoSuperMethodA( cl, o, msg );
  441.           }
  442.       }
  443.           break;
  444.  
  445. /****** anim.datatype/ADTM_START *********************************************
  446. *
  447. *    NAME
  448. *        ADTM_START -- Prepare for playback
  449. *
  450. *    FUNCTION
  451. *        ADTM_START tells the subclass (us) to prepare for continous
  452. *        playback. To avoid a long "search" for a full frame during the
  453. *        playback clock is running, we load here the given timestamp
  454. *        (asa_Frame) manually (and preseves it using a small trick, see
  455. *        source).
  456. *
  457. *        After all, the method is passed to superclass, which starts the
  458. *        playback (and the master clock).
  459. *
  460. *    RESULT
  461. *        Returns result from superclass (animation.datatype)
  462. *
  463. *    NOTE
  464. *
  465. ******************************************************************************
  466. *
  467. */
  468.  
  469.       case ADTM_START:
  470.       {
  471.           struct FrameNode *fn;
  472.           struct adtStart  *asa;
  473.           ULONG             timestamp;
  474.  
  475.           aid       = (struct AnimInstData *)INST_DATA( cl, o );
  476.           asa       = (struct adtStart *)msg;
  477.           timestamp = asa -> asa_Frame;
  478.  
  479.           ObtainSemaphore( (&(aid -> aid_SigSem)) );
  480.  
  481.           /* Turn on async IO */
  482.           aid -> aid_AsyncIO = TRUE;
  483.  
  484.           /* Find frame by timestamp */
  485.           if( fn = FindFrameNode( (&(aid -> aid_FrameList)), timestamp ) )
  486.           {
  487.             /* Load bitmaps only if we don't cache the whole anim and
  488.              * if we have a filehandle to load from (an empty object created using DTST_RAM don't have this)...
  489.              */
  490.             if( ((aid -> aid_LoadAll) == FALSE) && (aid -> aid_FH) )
  491.             {
  492.               /* If no bitmap is loaded, load it... */
  493.               if( (fn -> fn_BitMap) == NULL )
  494.               {
  495.                 struct adtFrame alf;
  496.  
  497.                 /* reset method msg */
  498.                 memset( (void *)(&alf), 0, sizeof( struct adtFrame ) );
  499.  
  500.                 /* load frame */
  501.                 alf . MethodID      = ADTM_LOADFRAME;
  502.                 alf . alf_TimeStamp = timestamp;
  503.                 alf . alf_Frame     = timestamp;
  504.  
  505.                 /* Load frame */
  506.                 if( DoMethodA( o, (Msg)(&alf) ) )
  507.                 {
  508.                   /* Success ! */
  509.  
  510.                   /* The "trick" used here is to decrase the fn_UseCount
  511.                    * WITHOUT unloading the bitmap. The first following
  512.                    * ADTM_LOADFRAME triggered by animation.datatypes playback
  513.                    * clock gets this frame without any problems
  514.                    */
  515.                   fn -> fn_UseCount--;
  516.                 }
  517.                 else
  518.                 {
  519.                   /* Failure ! */
  520.                   error_printf( cb, aid, "ADTM_START load error %ld", IoErr() );
  521.  
  522.                   /* Unload frame... */
  523.                   alf . MethodID = ADTM_UNLOADFRAME;
  524.                   DoMethodA( o, (Msg)(&alf) );
  525.                 }
  526.               }
  527.             }
  528.           }
  529.  
  530.           ReleaseSemaphore( (&(aid -> aid_SigSem)) );
  531.  
  532.           retval = DoSuperMethodA( cl, o, msg );
  533.       }
  534.           break;
  535.  
  536. /****** anim.datatype/ADTM_PAUSE **********************************************
  537. *
  538. *    NAME
  539. *        ADTM_PAUSE -- Pause playback
  540. *
  541. *    FUNCTION
  542. *        ADTM_PAUSE tells the subclass (use) to pause playback.
  543. *
  544. *        The method is passed to animation.datatype first, which pauses the
  545. *        playback clock.
  546. *
  547. *    RESULT
  548. *        Returns result from superclass (animation.datatype)
  549. *
  550. *    NOTE
  551. *
  552. ******************************************************************************
  553. *
  554. */
  555.  
  556.       case ADTM_PAUSE:
  557.       {
  558.           aid = (struct AnimInstData *)INST_DATA( cl, o );
  559.  
  560.           /* Pass msg to superclass first ! */
  561.           retval = DoSuperMethodA( cl, o, msg );
  562.  
  563.           ObtainSemaphore( (&(aid -> aid_SigSem)) );
  564.  
  565.             /* Return to syncrounous IO */
  566.             aid -> aid_AsyncIO = FALSE;
  567.  
  568.           ReleaseSemaphore( (&(aid -> aid_SigSem)) );
  569.       }
  570.           break;
  571.  
  572. /****** anim.datatype/ADTM_STOP **********************************************
  573. *
  574. *    NAME
  575. *        ADTM_STOP -- Stop playback
  576. *
  577. *    FUNCTION
  578. *        ADTM_STOP tells the subclass (use) to stop playback.
  579. *
  580. *        The method is passed to animation.datatype first, which stops the
  581. *        playback clock.
  582. *
  583. *        After clock has been stopped, we search for frames which have a
  584. *        0 UseCount and have not been unloaded yet (a small cleaup to get
  585. *        rid of frames which are loaded using the "trick" in ADTM_START
  586. *        code).
  587. *
  588. *    RESULT
  589. *        Returns result from superclass (animation.datatype)
  590. *
  591. *    NOTE
  592. *
  593. ******************************************************************************
  594. *
  595. */
  596.  
  597.  
  598.       case ADTM_STOP:
  599.       {
  600.           aid = (struct AnimInstData *)INST_DATA( cl, o );
  601.  
  602.           /* Pass msg to superclass first ! */
  603.           retval = DoSuperMethodA( cl, o, msg );
  604.  
  605.           ObtainSemaphore( (&(aid -> aid_SigSem)) );
  606.  
  607. #if 0
  608.           if( ((aid -> aid_LoadAll) == FALSE) && (aid -> aid_FH) )
  609.           {
  610.             struct FrameNode *worknode,
  611.                              *nextnode;
  612.  
  613.             worknode = (struct FrameNode *)(aid -> aid_FrameList . mlh_Head);
  614.  
  615.             while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  616.             {
  617.               /* Free an existing bitmap if it isn't in use and if it is NOT the first bitmap */
  618.               if( ((worknode -> fn_UseCount) == 0) && (worknode -> fn_BitMap) && (worknode != (struct FrameNode *)(aid -> aid_FrameList . mlh_Head)) )
  619.               {
  620.                 /* Don't free the current nor the previous nor the next bitmap (to avoid problems with delta frames) */
  621.                 if( (worknode != (aid -> aid_CurrFN)) &&
  622.                     (worknode != (struct FrameNode *)(aid -> aid_CurrFN -> fn_Node . mln_Succ)) &&
  623.                     (worknode != (struct FrameNode *)(aid -> aid_CurrFN -> fn_Node . mln_Pred)) )
  624.                 {
  625.                   FreeVecPooled( cb, (aid -> aid_FramePool), (worknode -> fn_BitMap) );
  626.                   worknode -> fn_BitMap = NULL;
  627.                 }
  628.               }
  629.  
  630.               worknode = nextnode;
  631.             }
  632.           }
  633. #endif
  634.  
  635.           /* Return to syncrounous IO */
  636.           aid -> aid_AsyncIO = FALSE;
  637.  
  638.           ReleaseSemaphore( (&(aid -> aid_SigSem)) );
  639.       }
  640.           break;
  641.  
  642.  
  643. /****** anim.datatype/ADTM_LOADFRAME *****************************************
  644. *
  645. *    NAME
  646. *        ADTM_LOADFRAME -- Load frame
  647. *
  648. *    FUNCTION
  649. *        The ADTM_LOADFRAME method is used to obtain the bitmap and timing
  650. *        data of the animation.
  651. *        The given timestamp will be used to find a matching timestamp
  652. *        in the internal FrameNode list. If it was found, the corresponding
  653. *        timing, bitmap and colormap data are stored into the struct
  654. *        adtFrame. If the bitmap wasn't loaded at this time, this method 
  655. *        attempts to load it from disk.
  656. *
  657. *    RESULT
  658. *        Returns the bitmap ptr if a bitmap was found, 0UL otherwise;
  659. *        in case of failure Result2 contains the cause:
  660. *        ERROR_OBJECT_NOT_FOUND: Given timestamp does not exist
  661. *        ERROR_NO_FREE_STORE:    No memory
  662. *        and so on...
  663. *
  664. *    NOTE
  665. *        It is expected that a 0 return code (error) causes an
  666. *        ADTM_UNLOADFRAME that the invalid bitmap etc. will be freed.
  667. *
  668. ******************************************************************************
  669. *
  670. */
  671.       case ADTM_LOADFRAME:
  672.       {
  673.           struct FrameNode *fn;
  674.           struct adtFrame  *alf;
  675.  
  676.           aid = (struct AnimInstData *)INST_DATA( cl, o );
  677.           alf = (struct adtFrame *)msg;
  678.  
  679.           ObtainSemaphore( (&(aid -> aid_SigSem)) );
  680.  
  681.           /* Like "realloc": Free any given frame here */
  682.           if( alf -> alf_UserData )
  683.           {
  684.             msg -> MethodID = ADTM_UNLOADFRAME;
  685.  
  686.               DoMethodA( o, msg );
  687.  
  688.             msg -> MethodID = ADTM_LOADFRAME;
  689.           }
  690.  
  691.           /* Find frame by timestamp */
  692.           if( fn = FindFrameNode( (&(aid -> aid_FrameList)), (alf -> alf_TimeStamp) ) )
  693.           {
  694.             LONG error = 0L;
  695.  
  696.             aid -> aid_CurrFN = fn;
  697.  
  698.             /* Load bitmaps only if we don't cache the whole anim and
  699.              * if we have a filehandle to load from (an empty object created using DTST_RAM don't have this)...
  700.              */
  701.             if( ((aid -> aid_LoadAll) == FALSE) && (aid -> aid_FH) )
  702.             {
  703.               /* If no bitmap is loaded, load it... */
  704.               if( (fn -> fn_BitMap) == NULL )
  705.               {
  706.                 if( fn -> fn_BitMap = AllocBitMapPooled( cb, (ULONG)(aid -> aid_BMH -> bmh_Width), (ULONG)(aid -> aid_BMH -> bmh_Height), (ULONG)(aid -> aid_BMH -> bmh_Depth), (aid -> aid_FramePool) ) )
  707.                 {
  708.                   struct FrameNode *worknode = fn;
  709.                   ULONG             rollback = 0UL;
  710.                   UBYTE            *buff;
  711.                   ULONG             buffsize;
  712.  
  713.                   /* Buffer to fill. Below we try to read some more bytes
  714.                    * (the size value is stored in worknode -> fn_LoadSize)
  715.                    * (ANHD chunk (~68 bytes), maybe a CMAP) to save
  716.                    * the Seek in the next cycle.
  717.                    * This makes only much sense when doing async io (during playback)...
  718.                    */
  719.  
  720.                   /* Not the last frame !
  721.                    * Note that this code is replicated in the loop below !!
  722.                    */
  723.  
  724.                   worknode -> fn_LoadSize = worknode -> fn_BMSize;
  725.  
  726.                   if( (worknode -> fn_Node . mln_Succ -> mln_Succ) && (aid -> aid_AsyncIO) )
  727.                   {
  728.                     ULONG nextpos = ((((struct FrameNode *)(worknode -> fn_Node . mln_Succ)) -> fn_BMOffset) + 8UL);
  729.  
  730.                     worknode -> fn_LoadSize = MAX( (worknode -> fn_LoadSize), (nextpos - ((worknode -> fn_BMOffset) + 8UL)) );
  731.  
  732.                     /* Don't alloc a too large buffer... */
  733.                     worknode -> fn_LoadSize = MIN( (worknode -> fn_LoadSize), ((worknode -> fn_BMSize) * 2UL) );
  734.                   }
  735.  
  736.                   buffsize = worknode -> fn_LoadSize;
  737.  
  738.                   do
  739.                   {
  740.                     worknode = worknode -> fn_PrevFrame;
  741.                     rollback++;
  742.  
  743.                     worknode -> fn_LoadSize = worknode -> fn_BMSize;
  744.  
  745.                     if( (worknode -> fn_Node . mln_Succ -> mln_Succ) && (aid -> aid_AsyncIO) )
  746.                     {
  747.                       ULONG nextpos = ((((struct FrameNode *)(worknode -> fn_Node . mln_Succ)) -> fn_BMOffset) + 8UL);
  748.  
  749.                       worknode -> fn_LoadSize = MAX( (worknode -> fn_LoadSize), (nextpos - ((worknode -> fn_BMOffset) + 8UL)) );
  750.  
  751.                       /* Don't alloc a too large buffer... */
  752.                       worknode -> fn_LoadSize = MIN( (worknode -> fn_LoadSize), ((worknode -> fn_BMSize) * 2UL) );
  753.                     }
  754.  
  755.                     buffsize = MAX( buffsize, (worknode -> fn_LoadSize) );
  756.                   } while( ((worknode -> fn_BitMap) == NULL) && ((worknode -> fn_TimeStamp) != 0UL) );
  757.  
  758.                   if( ((worknode -> fn_BitMap) == NULL) && ((worknode -> fn_TimeStamp) == 0UL) )
  759.                   {
  760.                     verbose_printf( cb, aid, "first frame without bitmap ... !\n" );
  761.                     ClearBitMap( (fn -> fn_BitMap) );
  762.                   }
  763.  
  764.                   /* Alloc buffer for compressed frame (DLTA) data */
  765.                   if( buff = (UBYTE *)AllocVecPooled( cb, (aid -> aid_Pool), (buffsize + 32UL) ) )
  766.                   {
  767.                     do
  768.                     {
  769.                       ULONG current = rollback;
  770.  
  771.                       worknode = fn;
  772.  
  773.                       while( current-- )
  774.                       {
  775.                         worknode = worknode -> fn_PrevFrame;
  776.                       }
  777.  
  778.                       if( (worknode -> fn_BitMap) && (worknode != fn) )
  779.                       {
  780.                         CopyBitMap( cb, (worknode -> fn_BitMap), (fn -> fn_BitMap) );
  781.                       }
  782.                       else
  783.                       {
  784.                         LONG seekdist; /* seeking distance (later Seek result, if Seek'ed) */
  785.  
  786.                         seekdist = (((worknode -> fn_BMOffset) + 8UL) - (aid -> aid_CurrFilePos));
  787.  
  788.                         /* Seek needed ? */
  789.                         if( seekdist != 0L )
  790.                         {
  791. #ifdef DOASYNCIO
  792.                           seekdist = SeekAsync( cb, (aid -> aid_FH), seekdist, OFFSET_CURRENT );
  793. #else
  794.                           seekdist = Seek( (aid -> aid_FH), seekdist, OFFSET_CURRENT );
  795. #endif /* DOASYNCIO */
  796.                         }
  797.  
  798.                         /* "Seek" success ? */
  799.                         if( seekdist != (-1L) )
  800.                         {
  801.                           LONG bytesread;
  802.  
  803. #ifdef DOASYNCIO
  804.                           bytesread = ReadAsync( cb, (aid -> aid_FH), buff, (worknode -> fn_LoadSize) );
  805. #else
  806.                           bytesread = Read( (aid -> aid_FH), buff, (worknode -> fn_LoadSize) );
  807. #endif /* DOASYNCIO */
  808.  
  809.                           /* No error during reading ? */
  810.                           if( (bytesread >= (worknode -> fn_BMSize)) && (bytesread != -1L) )
  811.                           {
  812.                             LONG ifferror;
  813.  
  814.                             if( ifferror = DrawDLTA( cb, aid, (fn -> fn_BitMap), (fn -> fn_BitMap), (&(worknode -> fn_AH)), buff, (worknode -> fn_BMSize) ) )
  815.                             {
  816.                               error_printf( cb, aid, "dlta unpacking error %lu\n", ifferror );
  817.  
  818.                               /* convert IFFParse error to DOS error */
  819.                               error = ifferr2doserr[ (-ifferror - 1) ];
  820.                             }
  821.  
  822.                             /* Bump file pos */
  823.                             aid -> aid_CurrFilePos = ((worknode -> fn_BMOffset) + 8UL) + bytesread;
  824.                           }
  825.                           else
  826.                           {
  827.                             /* Read error */
  828.                             error = IoErr();
  829.  
  830.                             /* Error, rewind stream */
  831. #ifdef DOASYNCIO
  832.                             SeekAsync( cb, (aid -> aid_FH), 0L, OFFSET_BEGINNING );
  833. #else
  834.                             Seek( (aid -> aid_FH), 0L, OFFSET_BEGINNING );
  835. #endif /* DOASYNCIO */
  836.                             aid -> aid_CurrFilePos = 0L;
  837.                           }
  838.  
  839.                           worknode -> fn_LoadSize = 0UL; /* destroy that this value won't affect anything else */
  840.                         }
  841.                         else
  842.                         {
  843.                           /* Seek error */
  844.                           error = IoErr();
  845.                         }
  846.                       }
  847.                     } while( rollback-- && (error == 0L) );
  848.  
  849.                     FreeVecPooled( cb, (aid -> aid_Pool), buff );
  850.                   }
  851.                   else
  852.                   {
  853.                     /* No memory for compressed frame data */
  854.                     error = ERROR_NO_FREE_STORE;
  855.                   }
  856.                 }
  857.                 else
  858.                 {
  859.                   /* No memory for frame bitmap */
  860.                   error = ERROR_NO_FREE_STORE;
  861.                 }
  862.               }
  863.             }
  864.  
  865.             /* Store frame/context information */
  866.             alf -> alf_Frame    = fn -> fn_Frame;
  867.             alf -> alf_Duration = fn -> fn_Duration;
  868.             alf -> alf_UserData = (APTR)fn;        /* Links back to this FrameNode (used by ADTM_UNLOADFRAME) */
  869.  
  870.             /* Store bitmap information */
  871.             alf -> alf_BitMap = fn -> fn_BitMap;
  872.             alf -> alf_CMap   = fn -> fn_CMap;
  873.  
  874.             /* Is there a sample to play ? */
  875.             if( fn -> fn_Sample )
  876.             {
  877.               /* Store sound information */
  878.               alf -> alf_Sample       = fn -> fn_Sample;
  879.               alf -> alf_SampleLength = fn -> fn_SampleLength;
  880.               alf -> alf_Period       = fn -> fn_Period;
  881.             }
  882.             else
  883.             {
  884.               /* No sound */
  885.               alf -> alf_Sample       = NULL;
  886.               alf -> alf_SampleLength = 0UL;
  887.               alf -> alf_Period       = 0UL;
  888.             }
  889.  
  890.             /* Frame "in use", even for a unsuccessful result; on error
  891.              * animation.datatype send an ADTM_UNLOADFRAME which frees
  892.              * allocated resources and decreases the "UseCount"...
  893.              */
  894.             fn -> fn_UseCount++;
  895.  
  896.             /* Is this node in the posted-free queue ? */
  897.             if( fn -> fn_PostedFree )
  898.             {
  899.               Remove( (struct Node *)(&(fn -> fn_PostedFreeNode)) );
  900.               fn -> fn_PostedFree = FALSE;
  901.             }
  902.  
  903.             retval = ((error)?(0UL):(ULONG)(alf -> alf_BitMap)); /* Result  */
  904.             SetIoErr( error );                                   /* Result2 */
  905.           }
  906.           else
  907.           {
  908.             /* no matching frame found */
  909.             SetIoErr( ERROR_OBJECT_NOT_FOUND );
  910.           }
  911.  
  912.           ReleaseSemaphore( (&(aid -> aid_SigSem)) );
  913.       }
  914.           break;
  915.  
  916. /****** anim.datatype/ADTM_UNLOADFRAME ***************************************
  917. *
  918. *    NAME
  919. *        ADTM_UNLOADFRAME -- Load frame contents
  920. *
  921. *    FUNCTION
  922. *        The ADTM_UNLOADFRAME method is used to release the contents of a
  923. *        animation frame.
  924. *
  925. *        This method frees the bitmap data found in adtFrame.
  926. *
  927. *    RESULT
  928. *        Returns always 0UL.
  929. *
  930. ******************************************************************************
  931. *
  932. */
  933.       case ADTM_UNLOADFRAME:
  934.       {
  935.           struct FrameNode *fn;
  936.           struct adtFrame  *alf;
  937.  
  938.           aid = (struct AnimInstData *)INST_DATA( cl, o );
  939.           alf = (struct adtFrame *)msg;
  940.  
  941.           /* Free bitmaps only if we don't cache the whole anim */
  942.           if( (aid -> aid_LoadAll) == FALSE )
  943.           {
  944.             struct MinNode *pfn;
  945.             UWORD           i   = 10;
  946.  
  947.             ObtainSemaphore( (&(aid -> aid_SigSem)) );
  948.  
  949.             if( fn = (struct FrameNode *)(alf -> alf_UserData) )
  950.             {
  951.               if( (fn -> fn_UseCount) > 0 )
  952.               {
  953.                 fn -> fn_UseCount--;
  954.  
  955.                 /* Free an existing bitmap if it isn't in use and if it is NOT the first bitmap */
  956.                 if( ((fn -> fn_UseCount) == 0) && (fn -> fn_BitMap) && (fn != (struct FrameNode *)(aid -> aid_FrameList . mlh_Head)) )
  957.                 {
  958.                   if( FALSE /*FreeAbleFrame( aid, fn )*/ )
  959.                   {
  960.                     /* Is this node in the posted-free queue ? */
  961.                     if( fn -> fn_PostedFree )
  962.                     {
  963.                       Remove( (struct Node *)(&(fn -> fn_PostedFreeNode)) );
  964.                       fn -> fn_PostedFree = FALSE;
  965.  
  966.                       D( kprintf( "free posted 1 %lu\n", (fn -> fn_TimeStamp) ) );
  967.                     }
  968.  
  969.                     FreeVecPooled( cb, (aid -> aid_FramePool), (fn -> fn_BitMap) );
  970.                     fn -> fn_BitMap = NULL;
  971.                   }
  972.                   else
  973.                   {
  974.                     if( (fn -> fn_PostedFree) == FALSE )
  975.                     {
  976.                       D( kprintf( "posted free %lu\n", (fn -> fn_TimeStamp) ) );
  977.  
  978.                       AddTail( (struct List *)(&(aid -> aid_PostedFreeList)), (struct Node *)(&(fn -> fn_PostedFreeNode)) );
  979.                       fn -> fn_PostedFree = TRUE;
  980.                     }
  981.                   }
  982.                 }
  983.               }
  984.             }
  985.  
  986.             while( pfn = (struct MinNode *)RemHead( (struct List *)(&(aid -> aid_PostedFreeList)) ) )
  987.             {
  988.               fn = POSTEDFREENODE2FN( pfn );
  989.               fn -> fn_PostedFree = FALSE;
  990.  
  991.               if( (fn -> fn_UseCount) == 0 )
  992.               {
  993.                 if( FreeAbleFrame( aid, fn ) )
  994.                 {
  995.                   D( kprintf( "free posted 2 %lu at %lu\n", (fn -> fn_TimeStamp), (((struct FrameNode *)(alf -> alf_UserData)) -> fn_TimeStamp) ) );
  996.  
  997.                   FreeVecPooled( cb, (aid -> aid_FramePool), (fn -> fn_BitMap) );
  998.                   fn -> fn_BitMap = NULL;
  999.                 }
  1000.                 else
  1001.                 {
  1002.                   AddTail( (struct List *)(&(aid -> aid_PostedFreeList)), (struct Node *)(&(fn -> fn_PostedFreeNode)) );
  1003.                   fn -> fn_PostedFree = TRUE;
  1004.                 }
  1005.  
  1006.                 /* Don't process the list twice */
  1007.                 if( fn == ((struct FrameNode *)(alf -> alf_UserData)) )
  1008.                 {
  1009.                   i = MIN( 1, i );
  1010.  
  1011.                   break;
  1012.                 }
  1013.  
  1014.                 if( i-- == 0 )
  1015.                 {
  1016.                   D( kprintf( "pl overflow at %lu\n", (((struct FrameNode *)(alf -> alf_UserData)) -> fn_TimeStamp) ) );
  1017.  
  1018.                   break;
  1019.                 }
  1020.               }
  1021.             }
  1022.  
  1023.             ReleaseSemaphore( (&(aid -> aid_SigSem)) );
  1024.           }
  1025.  
  1026.           /* Indicate that the frame has been free'ed. */
  1027.           alf -> alf_UserData = NULL;
  1028.       }
  1029.           break;
  1030.  
  1031.       /* Let the superclass handle everything else */
  1032.       default:
  1033.       {
  1034.           retval = DoSuperMethodA( cl, o, msg );
  1035.       }
  1036.           break;
  1037.     }
  1038.  
  1039.     return( retval );
  1040. }
  1041.  
  1042.  
  1043. static
  1044. BOOL FreeAbleFrame( struct AnimInstData *aid, struct FrameNode *fn )
  1045. {
  1046.     struct FrameNode *currfn = aid -> aid_CurrFN;
  1047.  
  1048.     /* Don't free the current nor the previous nor the next bitmap (to avoid problems with delta frames) */
  1049.     if( (fn == currfn) ||
  1050.         (fn == (struct FrameNode *)(currfn -> fn_Node . mln_Succ)) ||
  1051.         (fn == (struct FrameNode *)(currfn -> fn_Node . mln_Pred)) )
  1052.     {
  1053.       return( FALSE );
  1054.     }
  1055.  
  1056.     if( ABS( ((LONG)(fn -> fn_TimeStamp)) - ((LONG)(currfn -> fn_TimeStamp)) ) < 5UL )
  1057.     {
  1058.       return( FALSE );
  1059.     }
  1060.  
  1061.     return( TRUE );
  1062. }
  1063.  
  1064.  
  1065. /****** anim.datatype/preferences ********************************************
  1066. *
  1067. *   NAME
  1068. *       preferences
  1069. *
  1070. *   DESCRIPTION
  1071. *       The "ENV:Classes/DataTypes/anim.prefs" file contains global
  1072. *       settings for the datatype.
  1073. *       The preferences file is an ASCII file containing one line where the
  1074. *       preferences can be set.
  1075. *       It can be superset by a local variable with the same name.
  1076. *
  1077. *       Each line can contain settings, special settings for some projects
  1078. *       can be set using the MATCHPROJECT option.
  1079. *       Lines beginning with a '#' or ';' chars are treated as comments.
  1080. *       Lines are limitted to 256 chars.
  1081. *
  1082. *   TEMPLATE
  1083. *       MATCHPROJECT/K,VERBOSE/S,MODEID/K/N,CMAPS/S,NOCMAPS/S,
  1084. *       DPAINTBRUSHPATCH/S,NODPAINTBRUSHPATCH/S,FPS/K/N,DYNAMICTIMING/S,
  1085. *       NODYNAMICTIMING/S,SAMPLE/K,SAMPLESPERFRAME=SPF/K/N,VOLUME/K/N,
  1086. *       LOADALL/S,NOLOADALL/S
  1087. *
  1088. *       MATCHPROJECT -- The settings in this line belongs only to this
  1089. *           project(s), e.g. if the case-insensitive pattern does not match,
  1090. *           this line is ignored.
  1091. *           The maximum length of the pattern is 128 chars.
  1092. *           Defaults to #?, which matches any project.
  1093. *
  1094. *       VERBOSE -- Print information about the animation. Currently
  1095. *          the frame numbers and the used compression are printed, after all
  1096. *          number of scanned/loaded frames, set FPS rate, dimensions (width/
  1097. *          height/depth), sample information etc.
  1098. *
  1099. *       MODEID -- Select screen mode id of datatype (will be stored in
  1100. *           ADTA_ModeID). Note that the DOS ReadArgs function used for parsing
  1101. *           fetches a SIGNED long. The bit 31 will be represented by minus
  1102. *           '-'. (example: "MODEID=266240" sets the mode to the A2024 screen
  1103. *           mode id)
  1104. *           Defaults to 0, which means: Use the screen mode from CAMG chunk,
  1105. *           if missing use the best screenmode available for the given width,
  1106. *           height and depth.
  1107. *
  1108. *       CMAPS -- Use colormaps per frame. This switch is set per default,
  1109. *           and can be turned off by the NOCMAPS option, later it can be
  1110. *           turned on again by this option.
  1111. *
  1112. *       NOCMAPS -- Don't load/use colormaps per frame. Only the initial
  1113. *           colormap will be used.
  1114. *           The current version of animation.datatype (V40.7 (28.09.93)) does
  1115. *           not implement per frame colormaps, it's output may look trashed.
  1116. *           Custom players like "DBufDTAnim" does support
  1117. *           "per frame colormaps",
  1118. *           animation.datatype V41 will implement "per frame colormaps".
  1119. *
  1120. *       DPAINTBRUSHPATCH -- If frames of ANIM-5 with an interleave of 1
  1121. *           occurs, the XOR mode is forced, even if the XOR bit is not set.
  1122. *           This fixes problems with some DPaint brush animations.
  1123. *           This option is ON per default and can be turned off by the 
  1124. *           NODPAINTBRUSHPATCH option.
  1125. *
  1126. *       NODPAINTBRUSHPATCH -- Turns off the DPaint brush patch. See 
  1127. *           DPAINTBRUSHPATCH option for details.
  1128. *
  1129. *       FPS -- Frames Per Second
  1130. *           Defaults to FPS set by DPAN chunk. If the DPAN chunk is missing
  1131. *           a fixed 5 fps rate is used.
  1132. *           A value of 0 here means: Use default FPS.
  1133. *
  1134. *       DYNAMICTIMING -- Turns dynamic timing on. Default if superclass
  1135. *           is animation.datatype V41, otherwise this option must
  1136. *           be explicitly set.
  1137. *
  1138. *       NODYNAMICTIMING -- Turn dynamic timing off. Default if superclass
  1139. *           is animation.datatype < V41 (e.g. V40.6).
  1140. *
  1141. *       SAMPLE -- Attach the given sample to the animation. The sample will
  1142. *           be loaded using datatypes (GID_SOUND).
  1143. *           Only one sample can be attached to one animationstream, any
  1144. *           following attempt to attach a sample will be ignored.
  1145. *
  1146. *       SAMPLESPERFRAME -- Set samples per frame rate for sound. This
  1147. *           overrides the own internal calculations to get rid of rounding
  1148. *           errors.
  1149. *
  1150. *       VOLUME -- Volume of the sound when playing.
  1151. *           Defaults to 64, which is the maximum. A value greater than 64 will
  1152. *           be set to 64.
  1153. *
  1154. *       LOADALL -- Load all frames into memory. If the source input is a
  1155. *           clipboard, this option is always set.
  1156. *
  1157. *       NOLOADALL -- Turns off the LOADALL flag, which may be set in a prefs-
  1158. *           line before. This switch is set per default, and can be turned off
  1159. *           by the LOADALL option, later it can be turned on again by this
  1160. *           option.
  1161. *
  1162. *       REGISTERED -- Turns off the shareware notice requester.
  1163. *
  1164. *   NOTE
  1165. *       An invalid prefs file line will be ignored and forces the VERBOSE
  1166. *       output.
  1167. *
  1168. *   BUGS
  1169. *       - Low memory may cause that the prefs file won't be parsed.
  1170. *
  1171. *       - Lines are limitted to 256 chars
  1172. *
  1173. *       - An invalid prefs file line will be ignored.
  1174. *
  1175. *       - The sample path length is limitted to 200 chars. A larger
  1176. *         value may crash the machine if an error occurs.
  1177. *
  1178. ******************************************************************************
  1179. *
  1180. */
  1181.  
  1182.  
  1183. static
  1184. STRPTR GetPrefsVar( struct ClassBase *cb, STRPTR name )
  1185. {
  1186.           STRPTR buff;
  1187.     const ULONG  buffsize = 16UL;
  1188.  
  1189.     if( buff = (STRPTR)AllocVec( (buffsize + 2UL), (MEMF_PUBLIC | MEMF_CLEAR) ) )
  1190.     {
  1191.       if( GetVar( name, buff, buffsize, GVF_BINARY_VAR ) != (-1L) )
  1192.       {
  1193.         ULONG varsize = IoErr();
  1194.  
  1195.         varsize += 2UL;
  1196.  
  1197.         if( varsize > buffsize )
  1198.         {
  1199.           FreeVec( buff );
  1200.  
  1201.           if( buff = (STRPTR)AllocVec( (varsize + 2UL), (MEMF_PUBLIC | MEMF_CLEAR) ) )
  1202.           {
  1203.             if( GetVar( name, buff, varsize, GVF_BINARY_VAR ) != (-1L) )
  1204.             {
  1205.               return( buff );
  1206.             }
  1207.           }
  1208.         }
  1209.         else
  1210.         {
  1211.           return( buff );
  1212.         }
  1213.       }
  1214.  
  1215.       FreeVec( buff );
  1216.     }
  1217.  
  1218.     return( NULL );
  1219. }
  1220.  
  1221.  
  1222. static
  1223. BOOL matchstr( struct ClassBase *cb, STRPTR pat, STRPTR s )
  1224. {
  1225.     TEXT buff[ 512 ];
  1226.  
  1227.     if( pat && s )
  1228.     {
  1229.       if( ParsePatternNoCase( pat, buff, (sizeof( buff ) - 1) ) != (-1L) )
  1230.       {
  1231.         if( MatchPatternNoCase( buff, s ) )
  1232.         {
  1233.           return( TRUE );
  1234.         }
  1235.       }
  1236.     }
  1237.  
  1238.     return( FALSE );
  1239. }
  1240.  
  1241.  
  1242. static
  1243. void ReadENVPrefs( struct ClassBase *cb, struct AnimInstData *aid )
  1244. {
  1245.     struct RDArgs envvarrda =
  1246.     {
  1247.       NULL,
  1248.       256L,
  1249.       0L,
  1250.       0L,
  1251.       NULL,
  1252.       0L,
  1253.       NULL,
  1254.       RDAF_NOPROMPT
  1255.     };
  1256.  
  1257.     struct
  1258.     {
  1259.       STRPTR  matchproject;
  1260.       long   *verbose;
  1261.       long   *modeid;
  1262.       long   *cmaps;
  1263.       long   *nocmaps;
  1264.       long   *dpaintbrushpatch;
  1265.       long   *nodpaintbrushpatch;
  1266.       long   *fps;
  1267.       long   *dynamictiming;
  1268.       long   *nodynamictiming;
  1269.       STRPTR  sample;
  1270.       long   *samplesperframe;
  1271.       long   *volume;
  1272.       long   *loadall;
  1273.       long   *noloadall;
  1274.       long   *registered;
  1275.     } animargs;
  1276.  
  1277.     TEXT   varbuff[ 258 ];
  1278.     STRPTR var;
  1279.  
  1280.     if( var = GetPrefsVar( cb, "Classes/DataTypes/anim.prefs" ) )
  1281.     {
  1282.       STRPTR prefsline      = var,
  1283.              nextprefsline;
  1284.       ULONG  linecount      = 1UL;
  1285.  
  1286.       /* Be sure that "var" contains at least one break-char */
  1287.       strcat( var, "\n" );
  1288.  
  1289.       while( nextprefsline = strpbrk( prefsline, "\n" ) )
  1290.       {
  1291.         stccpy( varbuff, prefsline, (int)MIN( (sizeof( varbuff ) - 2UL), (((ULONG)(nextprefsline - prefsline)) + 1UL) ) );
  1292.  
  1293.         /* be sure that this line isn't a comment line or an empty line */
  1294.         if( (varbuff[ 0 ] != '#') && (varbuff[ 0 ] != ';') && (varbuff[ 0 ] != '\n') && (strlen( varbuff ) > 2UL) )
  1295.         {
  1296.           /* Prepare ReadArgs processing */
  1297.           strcat( varbuff, "\n" );                                       /* Add NEWLINE-char            */
  1298.           envvarrda . RDA_Source . CS_Buffer = varbuff;                  /* Buffer                      */
  1299.           envvarrda . RDA_Source . CS_Length = strlen( varbuff ) + 1UL;  /* Set up input buffer length  */
  1300.           envvarrda . RDA_Source . CS_CurChr = 0L;
  1301.           envvarrda . RDA_Buffer = NULL;
  1302.           envvarrda . RDA_BufSiz = 0L;
  1303.           memset( (void *)(&animargs), 0, sizeof( animargs ) );          /* Clear result array          */
  1304.  
  1305.           if( ReadArgs( "MATCHPROJECT/K,"
  1306.                         "VERBOSE/S,"
  1307.                         "MODEID/K/N,"
  1308.                         "CMAPS/S,"
  1309.                         "NOCMAPS/S,"
  1310.                         "DPAINTBRUSHPATCH/S,"
  1311.                         "NODPAINTBRUSHPATCH/S,"
  1312.                         "FPS/K/N,"
  1313.                         "DYNAMICTIMING/S,"
  1314.                         "NODYNAMICTIMING/S,"
  1315.                         "SAMPLE/K,"
  1316.                         "SAMPLESPERFRAME=SPF/K/N,"
  1317.                         "VOLUME/K/N,"
  1318.                         "LOADALL/S,"
  1319.                         "NOLOADALL/S,"
  1320.                         "REGISTERED/S", (LONG *)(&animargs), (&envvarrda) ) )
  1321.           {
  1322.             BOOL noignore = TRUE;
  1323.  
  1324.             if( (animargs . matchproject) && (aid -> aid_ProjectName) )
  1325.             {
  1326.               noignore = matchstr( cb, (animargs . matchproject), (aid -> aid_ProjectName) );
  1327.             }
  1328.  
  1329.             if( noignore )
  1330.             {
  1331.               if( animargs . verbose )
  1332.               {
  1333.                 OpenLogfile( cb, aid );
  1334.               }
  1335.  
  1336.               if( animargs . modeid )
  1337.               {
  1338.                 aid -> aid_ModeID = *(animargs . modeid);
  1339.               }
  1340.  
  1341.               if( animargs . cmaps )
  1342.               {
  1343.                 aid -> aid_NoCMAPs = FALSE;
  1344.               }
  1345.  
  1346.               if( animargs . nocmaps )
  1347.               {
  1348.                 aid -> aid_NoCMAPs = TRUE;
  1349.               }
  1350.  
  1351.               if( animargs . dpaintbrushpatch )
  1352.               {
  1353.                 aid -> aid_NoDPaintBrushPatch = FALSE;
  1354.               }
  1355.  
  1356.               if( animargs . nodpaintbrushpatch )
  1357.               {
  1358.                 aid -> aid_NoDPaintBrushPatch = TRUE;
  1359.               }
  1360.  
  1361.               if( animargs . fps )
  1362.               {
  1363.                 aid -> aid_FPS = *(animargs . fps);
  1364.               }
  1365.  
  1366.               if( animargs . dynamictiming )
  1367.               {
  1368.                 aid -> aid_NoDynamicTiming = FALSE;
  1369.               }
  1370.  
  1371.               if( animargs . nodynamictiming )
  1372.               {
  1373.                 aid -> aid_NoDynamicTiming = TRUE;
  1374.               }
  1375.  
  1376.               if( (animargs . sample) && ((aid -> aid_Sample) == NULL) )
  1377.               {
  1378.                 Object *so;
  1379.                 LONG    ioerr = 0L;
  1380.  
  1381.                 verbose_printf( cb, aid, "loading sample \"%s\"...\n", (animargs . sample) );
  1382.  
  1383.                 if( so = NewDTObject( (animargs . sample), DTA_GroupID, GID_SOUND, TAG_DONE ) )
  1384.                 {
  1385.                   BYTE  *sample;
  1386.                   ULONG  length;
  1387.                   ULONG  period;
  1388.  
  1389.                   /* Get sample data from object */
  1390.                   if( GetDTAttrs( so, SDTA_Sample,       (&sample),
  1391.                                       SDTA_SampleLength, (&length),
  1392.                                       SDTA_Period,       (&period),
  1393.                                       TAG_DONE ) == 3UL )
  1394.                   {
  1395.                     if( aid -> aid_Sample = (STRPTR)AllocPooled( (aid -> aid_Pool), (length + 1UL) ) )
  1396.                     {
  1397.                       /* Copy sample and context */
  1398.                       XCopyMem( cb, (APTR)sample, (APTR)(aid -> aid_Sample), length );
  1399.                       aid -> aid_SampleLength = length;
  1400.                       aid -> aid_Period       = period;
  1401.                     }
  1402.                     else
  1403.                     {
  1404.                       /* Can't alloc sample */
  1405.                       ioerr = ERROR_NO_FREE_STORE;
  1406.                     }
  1407.                   }
  1408.                   else
  1409.                   {
  1410.                     /* Object does not support the requested attributes */
  1411.                     ioerr = ERROR_OBJECT_WRONG_TYPE;
  1412.                   }
  1413.  
  1414.                   DisposeDTObject( so );
  1415.                 }
  1416.                 else
  1417.                 {
  1418.                   /* NewDTObjectA failed, cannot load sample... */
  1419.                   ioerr = IoErr();
  1420.                 }
  1421.  
  1422.                 if( (aid -> aid_Sample) == NULL )
  1423.                 {
  1424.                   TEXT errbuff[ 256 ];
  1425.  
  1426.                   if( ioerr >= DTERROR_UNKNOWN_DATATYPE )
  1427.                   {
  1428.                     mysprintf( cb, errbuff, GetDTString( ioerr ), (animargs . sample) );
  1429.                   }
  1430.                   else
  1431.                   {
  1432.                     Fault( ioerr, (animargs . sample), errbuff, sizeof( errbuff ) );
  1433.                   }
  1434.  
  1435.                   error_printf( cb, aid, "can't load sample: \"%s\" line %lu\n", errbuff, linecount );
  1436.                 }
  1437.               }
  1438.  
  1439.               if( animargs . samplesperframe )
  1440.               {
  1441.                 aid -> aid_SamplesPerFrame = (ULONG)(*(animargs . samplesperframe));
  1442.               }
  1443.  
  1444.               if( animargs . volume )
  1445.               {
  1446.                 aid -> aid_Volume = *(animargs . volume);
  1447.  
  1448.                 if( (aid -> aid_Volume) > 64UL )
  1449.                 {
  1450.                   aid -> aid_Volume = 64UL;
  1451.                 }
  1452.               }
  1453.  
  1454.               if( animargs . loadall )
  1455.               {
  1456.                 aid -> aid_LoadAll = TRUE;
  1457.               }
  1458.  
  1459.               if( animargs . noloadall )
  1460.               {
  1461.                 aid -> aid_LoadAll = FALSE;
  1462.               }
  1463.  
  1464.               if( animargs . registered )
  1465.               {
  1466.                 aid -> aid_Registered = TRUE;
  1467.               }
  1468.             }
  1469.             else
  1470.             {
  1471.               verbose_printf( cb, aid, "prefs line %lu ignored\n", linecount );
  1472.             }
  1473.  
  1474.             FreeArgs( (&envvarrda) );
  1475.           }
  1476.           else
  1477.           {
  1478.             LONG ioerr = IoErr();
  1479.             TEXT errbuff[ 256 ];
  1480.  
  1481.             Fault( ioerr, "Classes/DataTypes/anim.prefs", errbuff, (LONG)sizeof( errbuff ) );
  1482.  
  1483.             error_printf( cb, aid, "preferences \"%s\" line %lu\n", errbuff, linecount );
  1484.           }
  1485.         }
  1486.  
  1487.         prefsline = ++nextprefsline;
  1488.         linecount++;
  1489.       }
  1490.  
  1491.       FreeVec( var );
  1492.     }
  1493.  
  1494.     /* Notify the user that she/he is using shareware... */
  1495.     if( !(aid -> aid_Registered) )
  1496.     {
  1497.       YouShouldRegister( cb, aid );
  1498.     }
  1499. }
  1500.  
  1501.  
  1502. /* The shareware notify requester */
  1503. static
  1504. void YouShouldRegister( struct ClassBase *cb, struct AnimInstData *aid )
  1505. {
  1506.     struct EasyStruct SharewareES;
  1507.     ULONG             xa,
  1508.                       xb,
  1509.                       xc,
  1510.                       xd;
  1511.     ULONG             result;
  1512.     LONG              reqresult;
  1513.  
  1514.     TEXT              buffer[ 256 ],
  1515.                       cbuffer[ 256 ];
  1516. #define NUMCHOICES (6)
  1517.     ULONG             choices[ NUMCHOICES ];
  1518.  
  1519.     /* Create random values */
  1520.     CurrentTime( (&xb), (&xa) );
  1521.     xc = FastRand( xa );
  1522.     xd = FastRand( xb );
  1523.  
  1524.     /* Strip down to human-friendly values */
  1525.     xa %=  5;
  1526.     xb %=  7;
  1527.     xc %= 11;
  1528.     xd %= 13;
  1529.  
  1530.     /* calc */
  1531.     result = xa + xb * xc + xd;
  1532.  
  1533.     /* Build term */
  1534.     mysprintf( cb, buffer, "%lu + %lu * %lu + %lu = ???", xa, xb, xc, xd );
  1535.  
  1536.     /* Our choices */
  1537.     choices[ 0 ] = result;
  1538.     choices[ 1 ] = result + xb;
  1539.     choices[ 2 ] = result + xb + 1;
  1540.     choices[ 3 ] = result + xa / 2;
  1541.     choices[ 4 ] = result + 2 + xc;
  1542.     choices[ 5 ] = xa + xb + result / 2;
  1543.  
  1544.     mysprintf( cb, cbuffer, "%lu|%lu|%lu|%lu|%lu|%lu",
  1545.                choices[ (0 + xc) % NUMCHOICES ],
  1546.                choices[ (1 + xc) % NUMCHOICES ],
  1547.                choices[ (2 + xc) % NUMCHOICES ],
  1548.                choices[ (3 + xc) % NUMCHOICES ],
  1549.                choices[ (4 + xc) % NUMCHOICES ],
  1550.                choices[ (5 + xc) % NUMCHOICES ] );
  1551.  
  1552.     /* Prepare requester */
  1553.     SharewareES . es_StructSize   = sizeof( struct EasyStruct );
  1554.     SharewareES . es_Flags        = 0UL;
  1555.     SharewareES . es_Title        = "IFF ANIM DataType Shareware notice";
  1556.     SharewareES . es_TextFormat   = "Please register this DataType if you're using it more than 30 days\n"
  1557.                                     "See docs how to pay the shareware fee.\n"
  1558.                                     "To get rid of this requester forever, you must set the REGISTERED switch\n"
  1559.                                     "in the prefs-file \"ENVARC:Classes/DataTypes/anim.prefs\"\n"
  1560.                                     "then reboot the computer.\n"
  1561.                                     "To close the requester successfully, you must answer the following term:\n"
  1562.                                     "%s";
  1563.     SharewareES . es_GadgetFormat = cbuffer;
  1564.  
  1565.     /* The trial and error loop... */
  1566.     do
  1567.     {
  1568.       reqresult = EasyRequest( NULL, (&SharewareES), NULL, buffer );
  1569.  
  1570.       if( reqresult == 0L )
  1571.       {
  1572.         reqresult = NUMCHOICES;
  1573.       }
  1574.  
  1575.       reqresult--;
  1576.  
  1577.     } while( choices[ (reqresult + xc) % NUMCHOICES ] != result );
  1578. }
  1579.  
  1580.  
  1581. static
  1582. LONG LoadFrames( struct ClassBase *cb, Object *o )
  1583. {
  1584.     struct AnimInstData *aid   = (struct AnimInstData *)INST_DATA( (cb -> cb_Lib . cl_Class), o );
  1585.     LONG                 error = 0L;
  1586.  
  1587.     /* Init */
  1588.     InitSemaphore( (&(aid -> aid_SigSem)) );
  1589.     NewList( (struct List *)(&(aid -> aid_FrameList)) );
  1590.     NewList( (struct List *)(&(aid -> aid_PostedFreeList)) );
  1591.  
  1592.     /* Create a memory pool for frame nodes and delta buffers */
  1593.     if( aid -> aid_Pool = CreatePool( MEMF_PUBLIC, 32768UL, 32768UL ) )
  1594.     {
  1595.       APTR                 fh;                /* handle (IFF stream handle)      */
  1596.       ULONG                sourcetype;        /* type of stream (either DTST_FILE or DTST_CLIPBOARD */
  1597.       ULONG                pos        = 0UL;  /* current file pos in IFF stream  */
  1598.       struct BitMapHeader *bmh;               /* obj's bitmapheader              */
  1599.       ULONG                modeid     = 0UL;  /* anim view mode                  */
  1600.       ULONG                animwidth  = 0UL,  /* anim width                      */
  1601.                            animheight = 0UL,  /* anim height                     */
  1602.                            animdepth  = 0UL;  /* anim depth                      */
  1603.       ULONG                timestamp  = 0UL;  /* timestamp                       */
  1604.       ULONG                minreltime = 1UL,  /* Maximum ah_RelTime value        */
  1605.                            maxreltime = 0UL;  /* Minimum ah_RelTime              */
  1606.       struct tPoint       *grabpoint  = NULL; /* Grabbing point of animation     */
  1607.  
  1608.       /* Prefs defaults */
  1609.       aid -> aid_Volume          = 64UL;
  1610.       aid -> aid_NoDynamicTiming = MAKEBOOL( ((cb -> cb_SuperClassBase -> lib_Version) < 41U) );
  1611.  
  1612.       /* Read prefs */
  1613.       ReadENVPrefs( cb, aid );
  1614.  
  1615.       /* Get file handle, handle type and BitMapHeader */
  1616.       if( GetDTAttrs( o, DTA_SourceType,    (&sourcetype),
  1617.                          DTA_Handle,        (&fh),
  1618.                          DTA_Name,          (&(aid -> aid_ProjectName)),
  1619.                          ADTA_BitMapHeader, (&bmh),
  1620.                          ADTA_Grab,         (&grabpoint), /* animation.datatype V41 */
  1621.                          TAG_DONE ) >= 4UL ) /* ADTA_Grab not supported in V40, e.g. 4 == V40, 5 == V41 */
  1622.       {
  1623.         struct IFFHandle *iff = NULL;
  1624.  
  1625.         aid -> aid_BMH = bmh; /* Store BitMapHeader */
  1626.  
  1627.         switch( sourcetype )
  1628.         {
  1629.           case DTST_CLIPBOARD:
  1630.           {
  1631.               aid -> aid_LoadAll = TRUE;
  1632.  
  1633.               iff = (struct IFFHandle *)fh;
  1634.           }
  1635.               break;
  1636.  
  1637.           case DTST_FILE:
  1638.           {
  1639.               BPTR iff_file_fh;
  1640.               BPTR cloned_fh    = NULL;
  1641.  
  1642.               iff = (struct IFFHandle *)fh;
  1643.  
  1644.               /* Attempt to open file from given stream (allows usage of virtual fs when using datatypes.library V45) */
  1645.               iff_file_fh = (BPTR)(iff -> iff_Stream); /* see iffparse.library/InitIFFasDOS autodoc */
  1646.  
  1647.               if( iff_file_fh )
  1648.               {
  1649.                 BPTR lock;
  1650.  
  1651.                 if( lock = DupLockFromFH( iff_file_fh ) )
  1652.                 {
  1653.                   /* Set up a filehandle for disk-based loading (random loading) */
  1654.                   if( !(cloned_fh = (LONG)OpenFromLock( lock )) )
  1655.                   {
  1656.                     /* failure */
  1657.                     UnLock( lock );
  1658.                   }
  1659.                 }
  1660.               }
  1661.  
  1662.               /* OpenFromLock failed ? - Then open by name :-( */
  1663.               if( cloned_fh == NULL )
  1664.               {
  1665.                 /* Set up a filehandle for disk-based loading (random loading) */
  1666.                 if( !(cloned_fh = (LONG)Open( (aid -> aid_ProjectName), MODE_OLDFILE )) )
  1667.                 {
  1668.                   /* Can't open file */
  1669.                   error = IoErr();
  1670.                 }
  1671.               }
  1672.  
  1673.               if( cloned_fh )
  1674.               {
  1675. #ifdef DOASYNCIO
  1676.                 if( !(aid -> aid_FH = OpenAsync( cb, cloned_fh, 8192L )) )
  1677.                 {
  1678.                   /* Can't get async access */
  1679.                   error = IoErr();
  1680.                 }
  1681. #else
  1682.                 aid -> aid_FH = cloned_fh;
  1683. #endif /* DOASYNCIO */
  1684.               }
  1685.           }
  1686.               break;
  1687.  
  1688.           case DTST_RAM:
  1689.           {
  1690.               /* do nothing */
  1691.           }
  1692.               break;
  1693.  
  1694.           default:
  1695.           {
  1696.               /* unsupported source type */
  1697.               error = ERROR_NOT_IMPLEMENTED;
  1698.           }
  1699.               break;
  1700.         }
  1701.  
  1702.         /* Any error ? */
  1703.         if( error == 0L )
  1704.         {
  1705.           if( iff )
  1706.           {
  1707.             struct StoredProperty *bmhdprop       = NULL, /* ILBM BMHD (struct BitMapHeader)        */
  1708.                                   *camgprop       = NULL, /* ILBM CAMG (amiga view mode id)         */
  1709.                                   *grabprop       = NULL, /* ILBM GRAB (grabbing point)             */
  1710.                                   *dpanprop       = NULL, /* DPaint DPAN chunk                      */
  1711.                                   *annoprop       = NULL, /* Generic IFF ANNO (annotation) chunk    */
  1712.                                   *authprop       = NULL, /* Generic IFF AUTH (author) chunk        */
  1713.                                   *copyrightprop  = NULL, /* Generic IFF (C)  (copyright) chunk     */
  1714.                                   *fverprop       = NULL, /* Generic IFF FVER (version) chunk       */
  1715.                                   *nameprop       = NULL; /* Generic IFF NAME (name) chunk          */
  1716.  
  1717. #define NUM_PROPCHUNKS (9L)
  1718.             const
  1719.             LONG propchunks[ (NUM_PROPCHUNKS * 2) ] =
  1720.             {
  1721.               ID_ILBM, ID_BMHD,
  1722.               ID_ILBM, ID_CAMG,
  1723.               ID_ILBM, ID_GRAB,
  1724.               ID_ILBM, ID_DPAN,
  1725.               ID_ILBM, ID_ANNO,
  1726.               ID_ILBM, ID_AUTH,
  1727.               ID_ILBM, ID_Copyright,
  1728.               ID_ILBM, ID_FVER,
  1729.               ID_ILBM, ID_NAME
  1730.             };
  1731.  
  1732.             if( !(error = PropChunks( iff, (LONG *)propchunks, NUM_PROPCHUNKS )) )
  1733.             {
  1734. #define NUM_STOPCHUNKS (5L)
  1735.               const
  1736.               LONG stopchunks[ (NUM_STOPCHUNKS * 2) ] =
  1737.               {
  1738.                 ID_ILBM, ID_FORM,
  1739.                 ID_ILBM, ID_ANHD,
  1740.                 ID_ILBM, ID_CMAP,
  1741.                 ID_ILBM, ID_BODY,
  1742.                 ID_ILBM, ID_DLTA
  1743.               };
  1744.  
  1745.               if( !(error = StopChunks( iff, (LONG *)stopchunks, NUM_STOPCHUNKS )) )
  1746.               {
  1747.                 struct FrameNode *fn         = NULL;
  1748.                 ULONG             numcmaps   = 0UL; /* number of created cmaps  */
  1749.  
  1750.                 /* Scan IFF stream until an error or an EOF occurs */
  1751.                 for( ;; )
  1752.                 {
  1753.                   struct ContextNode *cn;
  1754.  
  1755.                   if( error = ParseIFF( iff, IFFPARSE_SCAN ) )
  1756.                   {
  1757.                     /* EOF (End Of File) is no error here... */
  1758.                     if( error == IFFERR_EOF )
  1759.                     {
  1760.                       error = 0L;
  1761.                     }
  1762.  
  1763.                     break;
  1764.                   }
  1765.  
  1766.                   /* Get file position */
  1767.                   if( cn = CurrentChunk( iff ) )
  1768.                   {
  1769.                     pos = 0UL;
  1770.  
  1771.                     while( cn = ParentChunk( cn ) )
  1772.                     {
  1773.                       pos += cn -> cn_Scan;
  1774.                     }
  1775.                   }
  1776.  
  1777.                   /* bmhd header loaded ? */
  1778.                   if( bmhdprop == NULL )
  1779.                   {
  1780.                     if( bmhdprop = FindProp( iff, ID_ILBM, ID_BMHD ) )
  1781.                     {
  1782.                       ULONG poolsize,
  1783.                             availmem;
  1784.  
  1785.                       *bmh = *((struct BitMapHeader *)(bmhdprop -> sp_Data));
  1786.  
  1787.                       animwidth  = bmh -> bmh_Width;
  1788.                       animheight = bmh -> bmh_Height;
  1789.                       animdepth  = bmh -> bmh_Depth;
  1790.  
  1791.                       availmem = AvailMem( MEMF_PUBLIC );
  1792.  
  1793.                       /* Create a seperate pool for frames:
  1794.                        * (((width + 7) / 8) * height * depth + struct BitMapHeader + Padding) * 4 frames
  1795.                        */
  1796.                       poolsize = (((animwidth * animheight * animdepth) / 8UL) + 256UL) * 4UL;
  1797.  
  1798.                       /* Shrink pool to a fitting size */
  1799.                       while( (poolsize * 4) > availmem )
  1800.                       {
  1801.                         poolsize /= 2UL;
  1802.                       }
  1803.  
  1804.                       /* Create a memory pool for frame bitmaps */
  1805.                       if( !(aid -> aid_FramePool = CreatePool( MEMF_PUBLIC, poolsize, poolsize )) )
  1806.                       {
  1807.                         error = ERROR_NO_FREE_STORE;
  1808.                       }
  1809.                     }
  1810.                   }
  1811.  
  1812.                   /* camg loaded ? */
  1813.                   if( camgprop == NULL )
  1814.                   {
  1815.                     if( camgprop = FindProp( iff, ID_ILBM, ID_CAMG ) )
  1816.                     {
  1817.                       modeid = *(ULONG *)(camgprop -> sp_Data);
  1818.  
  1819.                       /* Check for invalid flags */
  1820.                       if( (!(modeid & MONITOR_ID_MASK)) ||
  1821.                           ((modeid & EXTENDED_MODE) &&
  1822.                           (!(modeid & 0xFFFF0000UL))) )
  1823.                       {
  1824.                         /* Remove invalid flags (see include31:graphics/view.h) */
  1825.                         modeid &= ~(GENLOCK_VIDEO | PFBA | GENLOCK_AUDIO | DUALPF | EXTENDED_MODE | VP_HIDE | SPRITES );
  1826.                       }
  1827.  
  1828.                       /* Be safe ! */
  1829.                       if( (modeid & 0xFFFF0000UL) && (!(modeid & 0x00001000UL)) )
  1830.                       {
  1831.                         modeid = 0UL;
  1832.                       }
  1833.                     }
  1834.                   }
  1835.  
  1836.                   /* grab loaded ? */
  1837.                   if( grabprop == NULL )
  1838.                   {
  1839.                     if( grabprop = FindProp( iff, ID_ILBM, ID_GRAB ) )
  1840.                     {
  1841.                       /* Grab point only available in animation.datatype V41 */
  1842.                       if( grabpoint )
  1843.                       {
  1844.                         *grabpoint = *((struct tPoint *)(grabprop -> sp_Data));
  1845.                       }
  1846.  
  1847.                       verbose_printf( cb, aid, "animation GRAB point x=%ld, y=%ld\n",
  1848.                                       (long)(((struct tPoint *)(grabprop -> sp_Data)) -> x),
  1849.                                       (long)(((struct tPoint *)(grabprop -> sp_Data)) -> y) );
  1850.                     }
  1851.                   }
  1852.  
  1853.                   /* dpan loaded ? */
  1854.                   if( dpanprop == NULL )
  1855.                   {
  1856.                     if( dpanprop = FindProp( iff, ID_ILBM, ID_DPAN ) )
  1857.                     {
  1858.                       if( (aid -> aid_FPS) == 0UL )
  1859.                       {
  1860.                         struct DPAnimChunk *dpan = (struct DPAnimChunk *)(dpanprop -> sp_Data);
  1861.                         
  1862.                         if( (dpan -> dpan_FPS) <= 60UL )
  1863.                         {
  1864.                           aid -> aid_FPS = dpan -> dpan_FPS;
  1865.  
  1866.                           verbose_printf( cb, aid, "DPAN found, FPS set to %lu\n", (aid -> aid_FPS) );
  1867.                         }
  1868.                         else
  1869.                         {
  1870.                           verbose_printf( cb, aid, "DPAN found, ignoring invalid FPS value %lu\n", (ULONG)(dpan -> dpan_FPS) );
  1871.                         }
  1872.                       }
  1873.                     }
  1874.                   }
  1875.  
  1876.                   if( annoprop == NULL )
  1877.                   {
  1878.                     /* IFF ANNO found ? */
  1879.                     if( annoprop = FindProp( iff, ID_ILBM, ID_ANNO ) )
  1880.                     {
  1881.                       STRPTR buff;
  1882.  
  1883.                       /* Allocate a temp buffer so that stccpy can add a '\0'-terminator */
  1884.                       if( buff = (STRPTR)AllocVec( ((annoprop -> sp_Size) + 2UL), MEMF_ANY ) )
  1885.                       {
  1886.                         stccpy( buff, (annoprop -> sp_Data), (int)(annoprop -> sp_Size) );
  1887.  
  1888.                         verbose_printf( cb, aid, "ANNO annotation: \"%s\"\n", buff );
  1889.  
  1890.                         SetDTAttrs( o, NULL, NULL, DTA_ObjAnnotation, buff, TAG_DONE );
  1891.  
  1892.                         FreeVec( buff );
  1893.                       }
  1894.                       else
  1895.                       {
  1896.                         /* no temp. buffer */
  1897.                         error = ERROR_NO_FREE_STORE;
  1898.                       }
  1899.                     }
  1900.                   }
  1901.  
  1902.                   if( authprop == NULL )
  1903.                   {
  1904.                     /* IFF AUTH found ? */
  1905.                     if( authprop = FindProp( iff, ID_ILBM, ID_AUTH ) )
  1906.                     {
  1907.                       STRPTR buff;
  1908.  
  1909.                       /* Allocate a temp buffer so that stccpy can add a '\0'-terminator */
  1910.                       if( buff = (STRPTR)AllocVec( ((authprop -> sp_Size) + 2UL), MEMF_ANY ) )
  1911.                       {
  1912.                         stccpy( buff, (authprop -> sp_Data), (int)(authprop -> sp_Size) );
  1913.  
  1914.                         verbose_printf( cb, aid, "AUTH author: \"%s\"\n", buff );
  1915.  
  1916.                         SetDTAttrs( o, NULL, NULL, DTA_ObjAuthor, buff, TAG_DONE );
  1917.  
  1918.                         FreeVec( buff );
  1919.                       }
  1920.                       else
  1921.                       {
  1922.                         /* no temp. buffer */
  1923.                         error = ERROR_NO_FREE_STORE;
  1924.                       }
  1925.                     }
  1926.                   }
  1927.  
  1928.                   if( copyrightprop == NULL )
  1929.                   {
  1930.                     /* IFF (C) found ? */
  1931.                     if( copyrightprop = FindProp( iff, ID_ILBM, ID_Copyright ) )
  1932.                     {
  1933.                       STRPTR buff;
  1934.  
  1935.                       /* Allocate a temp buffer so that stccpy can add a '\0'-terminator */
  1936.                       if( buff = (STRPTR)AllocVec( ((copyrightprop -> sp_Size) + 2UL), MEMF_ANY ) )
  1937.                       {
  1938.                         stccpy( buff, (copyrightprop -> sp_Data), (int)(copyrightprop -> sp_Size) );
  1939.  
  1940.                         verbose_printf( cb, aid, "(C) copyright: \"%s\"\n", buff );
  1941.  
  1942.                         SetDTAttrs( o, NULL, NULL, DTA_ObjCopyright, buff, TAG_DONE );
  1943.  
  1944.                         FreeVec( buff );
  1945.                       }
  1946.                       else
  1947.                       {
  1948.                         /* no temp. buffer */
  1949.                         error = ERROR_NO_FREE_STORE;
  1950.                       }
  1951.                     }
  1952.                   }
  1953.  
  1954.                   if( fverprop == NULL )
  1955.                   {
  1956.                     /* IFF FVER found ? */
  1957.                     if( fverprop = FindProp( iff, ID_ILBM, ID_FVER ) )
  1958.                     {
  1959.                       STRPTR buff;
  1960.  
  1961.                       /* Allocate a temp buffer so that stccpy can add a '\0'-terminator */
  1962.                       if( buff = (STRPTR)AllocVec( ((fverprop -> sp_Size) + 2UL), MEMF_ANY ) )
  1963.                       {
  1964.                         stccpy( buff, (fverprop -> sp_Data), (int)(fverprop -> sp_Size) );
  1965.  
  1966.                         verbose_printf( cb, aid, "FVER version: \"%s\"\n", buff );
  1967.  
  1968.                         SetDTAttrs( o, NULL, NULL, DTA_ObjVersion, buff, TAG_DONE );
  1969.  
  1970.                         FreeVec( buff );
  1971.                       }
  1972.                       else
  1973.                       {
  1974.                         /* no temp. buffer */
  1975.                         error = ERROR_NO_FREE_STORE;
  1976.                       }
  1977.                     }
  1978.                   }
  1979.  
  1980.                   if( nameprop == NULL )
  1981.                   {
  1982.                     /* IFF NAME found ? */
  1983.                     if( nameprop = FindProp( iff, ID_ILBM, ID_NAME ) )
  1984.                     {
  1985.                       STRPTR buff;
  1986.  
  1987.                       /* Allocate a temp buffer so that stccpy can add a '\0'-terminator */
  1988.                       if( buff = (STRPTR)AllocVec( ((nameprop -> sp_Size) + 2UL), MEMF_ANY ) )
  1989.                       {
  1990.                         stccpy( buff, (nameprop -> sp_Data), (int)(nameprop -> sp_Size) );
  1991.  
  1992.                         verbose_printf( cb, aid, "NAME name: \"%s\"\n", buff );
  1993.  
  1994.                         SetDTAttrs( o, NULL, NULL, DTA_ObjName, buff, TAG_DONE );
  1995.  
  1996.                         FreeVec( buff );
  1997.                       }
  1998.                       else
  1999.                       {
  2000.                         /* no temp. buffer */
  2001.                         error = ERROR_NO_FREE_STORE;
  2002.                       }
  2003.                     }
  2004.                   }
  2005.  
  2006.                   if( cn = CurrentChunk( iff ) )
  2007.                   {
  2008.                     switch( (cn -> cn_Type) )
  2009.                     {
  2010.                       case ID_ILBM:
  2011.                       {
  2012.                           switch( (cn -> cn_ID) )
  2013.                           {
  2014.                             case ID_FORM:
  2015.                             {
  2016.                                 /* Create an prepare a new frame node */
  2017.                                 if( fn = AllocFrameNode( cb, (aid -> aid_Pool) ) )
  2018.                                 {
  2019.                                   AddTail( (struct List *)(&(aid -> aid_FrameList)), (struct Node *)(&(fn -> fn_Node)) );
  2020.  
  2021.                                   fn -> fn_TimeStamp = timestamp++;
  2022.                                   fn -> fn_Frame     = fn -> fn_TimeStamp;
  2023.                                   
  2024.                                   fn -> fn_PrevFrame = fn;
  2025.                                 }
  2026.                                 else
  2027.                                 {
  2028.                                   /* can't alloc frame node */
  2029.                                   error = ERROR_NO_FREE_STORE;
  2030.                                 }
  2031.                             }
  2032.                                 break;
  2033.  
  2034.                             case ID_ANHD:
  2035.                             {
  2036.                                 if( fn )
  2037.                                 {
  2038.                                   ULONG interleave;
  2039.  
  2040.                                   /* Read struct AnimHeader */
  2041.                                   error = ReadChunkBytes( iff, (&(fn -> fn_AH)), (LONG)sizeof( struct AnimHeader ) );
  2042.                                   if( error == (LONG)sizeof( struct AnimHeader ) ) error = 0L;
  2043.  
  2044.                                   /* Info */
  2045.                                   DumpAnimHeader( cb, aid, (fn -> fn_TimeStamp), (&(fn -> fn_AH)) );
  2046.  
  2047.                                   /* Check if we have dynamic timing */
  2048.                                   maxreltime = MAX( maxreltime, (fn -> fn_AH . ah_RelTime) );
  2049.                                   minreltime = MIN( minreltime, (fn -> fn_AH . ah_RelTime) );
  2050.  
  2051.                                   interleave = (ULONG)(fn -> fn_AH . ah_Interleave);
  2052.  
  2053.                                   /* An interleave of 0 means two frames back */
  2054.                                   if( interleave == 0 )
  2055.                                   {
  2056.                                     interleave = 2;
  2057.                                   }
  2058.  
  2059.                                   /* Get previous frame */
  2060.                                   fn -> fn_PrevFrame = GetPrevFrameNode( fn, interleave );
  2061.                                 }
  2062.                             }
  2063.                                 break;
  2064.  
  2065.                             case ID_CMAP:
  2066.                             {
  2067.                                 if( fn )
  2068.                                 {
  2069.                                   UBYTE *buff;
  2070.  
  2071.                                   /* Allocate buffer */
  2072.                                   if( buff = (UBYTE *)AllocVecPooled( cb, (aid -> aid_Pool), ((cn -> cn_Size) + 16UL) ) )
  2073.                                   {
  2074.                                     /* Load CMAP data */
  2075.                                     error = ReadChunkBytes( iff, buff, (cn -> cn_Size) );
  2076.  
  2077.                                     /* All read ? */
  2078.                                     if( error == (cn -> cn_Size) )
  2079.                                     {
  2080.                                       error = 0L; /* Success ! */
  2081.  
  2082.                                       if( timestamp == 1UL )
  2083.                                       {
  2084.                                         if( !CMAP2Object( cb, o, buff, (cn -> cn_Size) ) )
  2085.                                         {
  2086.                                           /* can't alloc object's color table */
  2087.                                           error = ERROR_NO_FREE_STORE;
  2088.                                         }
  2089.                                       }
  2090.  
  2091.                                       /* Any failure ? */
  2092.                                       if( error == 0L )
  2093.                                       {
  2094.                                         if( aid -> aid_NoCMAPs )
  2095.                                         {
  2096.                                           error = 0L; /* Success ! */
  2097.                                         }
  2098.                                         else
  2099.                                         {
  2100.                                           if( fn -> fn_CMap = CMAP2ColorMap( cb, aid, buff, (cn -> cn_Size) ) )
  2101.                                           {
  2102.                                             error = 0L; /* Success ! */
  2103.                                             numcmaps++;
  2104.                                           }
  2105.                                           else
  2106.                                           {
  2107.                                             /* no colormap */
  2108.                                             error = ERROR_NO_FREE_STORE;
  2109.                                           }
  2110.                                         }
  2111.                                       }
  2112.                                     }
  2113.  
  2114.                                     FreeVecPooled( cb, (aid -> aid_Pool), buff );
  2115.                                   }
  2116.                                   else
  2117.                                   {
  2118.                                     /* no load buff */
  2119.                                     error = ERROR_NO_FREE_STORE;
  2120.                                   }
  2121.                                 }
  2122.                             }
  2123.                                 break;
  2124.  
  2125.                             case ID_BODY:
  2126.                             case ID_DLTA:
  2127.                             {
  2128.                                 if( fn )
  2129.                                 {
  2130.                                   /* Store position of DLTA (pos points to the DLTA ID) */
  2131.                                   fn -> fn_BMOffset = pos;
  2132.                                   fn -> fn_BMSize   = cn -> cn_Size;
  2133.  
  2134.                                   if( (fn -> fn_BitMap) == NULL )
  2135.                                   {
  2136.                                     /* Preload frames only if requested or if this is the key frame (first frame of anim) */
  2137.                                     if( (aid -> aid_LoadAll) || ((fn -> fn_TimeStamp) == 0UL) )
  2138.                                     {
  2139.                                       if( animwidth && animheight && animdepth )
  2140.                                       {
  2141.                                         if( fn -> fn_BitMap = AllocBitMapPooled( cb, animwidth, animheight, animdepth, (aid -> aid_FramePool) ) )
  2142.                                         {
  2143.                                           UBYTE *buff;
  2144.  
  2145.                                           /* Allocate buffer */
  2146.                                           if( buff = (UBYTE *)AllocVecPooled( cb, (aid -> aid_Pool), ((cn -> cn_Size) + 32UL) ) )
  2147.                                           {
  2148.                                             struct FrameNode *prevfn;
  2149.  
  2150.                                             /* Clear buffer to get rid of some problems with corrupted DLTAs */
  2151.                                             memset( (void *)buff, 0, (size_t)((cn -> cn_Size) + 31UL) );
  2152.  
  2153.                                             /* Get previous frame */
  2154.                                             prevfn = fn -> fn_PrevFrame;
  2155.  
  2156.                                             /* Load delta data */
  2157.                                             error = ReadChunkBytes( iff, buff, (cn -> cn_Size) );
  2158.  
  2159.                                             /* All bytes read ? */
  2160.                                             if( error == (cn -> cn_Size) )
  2161.                                             {
  2162.                                               error = DrawDLTA( cb, aid, (prevfn -> fn_BitMap), (fn -> fn_BitMap), (&(fn -> fn_AH)), buff, (cn -> cn_Size) );
  2163.  
  2164.                                               if( error )
  2165.                                               {
  2166.                                                 error_printf( cb, aid, "scan/load: dlta unpacking error %lu\n", error );
  2167.                                               }
  2168.                                             }
  2169.  
  2170.                                             FreeVecPooled( cb, (aid -> aid_Pool), buff );
  2171.                                           }
  2172.                                           else
  2173.                                           {
  2174.                                             /* no load buff */
  2175.                                             error = ERROR_NO_FREE_STORE;
  2176.                                           }
  2177.                                         }
  2178.                                         else
  2179.                                         {
  2180.                                           /* no bitmap */
  2181.                                           error = ERROR_NO_FREE_STORE;
  2182.                                         }
  2183.                                       }
  2184.                                       else
  2185.                                       {
  2186.                                         /* no dimensions for bitmap (possibly a missing bmhd) */
  2187.                                         error = DTERROR_NOT_ENOUGH_DATA;
  2188.                                       }
  2189.                                     }
  2190.                                   }
  2191.                                   else
  2192.                                   {
  2193.                                     error_printf( cb, aid, "scan/load: bitmap already loaded\n" );
  2194.                                   }
  2195.                                 }
  2196.                             }
  2197.                                 break;
  2198.                           }
  2199.                       }
  2200.                           break;
  2201.                     }
  2202.                   }
  2203.  
  2204.                   /* on error: leave for-loop */
  2205.                   if( error )
  2206.                   {
  2207.                     break;
  2208.                   }
  2209.                 }
  2210.  
  2211.                 /* Any frames ? */
  2212.                 if( timestamp && (error == 0L) && numcmaps )
  2213.                 {
  2214.                   if( numcmaps == 1UL )
  2215.                   {
  2216.                     /* We only have a global colormap and no colormap changes,
  2217.                      * delete first colormap (a colormap in the first frames indicates following colormap
  2218.                      * changes)
  2219.                      */
  2220.                     struct FrameNode *firstnode = (struct FrameNode *)(aid -> aid_FrameList . mlh_Head);
  2221.  
  2222.                     if( firstnode -> fn_CMap )
  2223.                     {
  2224.                       FreeColorMap( (firstnode -> fn_CMap) );
  2225.                       firstnode -> fn_CMap = NULL;
  2226.                     }
  2227.                   }
  2228.                   else
  2229.                   {
  2230.                     /* All frames must have a colormap, therefore we replicate the colormap
  2231.                      * from the previous colormap if one is missing
  2232.                      */
  2233.                     struct FrameNode *worknode,
  2234.                                      *nextnode;
  2235.                     struct ColorMap  *currcm = NULL;
  2236.  
  2237.                     verbose_printf( cb, aid, "Animation has palette changes per frame\n" );
  2238.  
  2239.                     worknode = (struct FrameNode *)(aid -> aid_FrameList . mlh_Head);
  2240.  
  2241.                     while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  2242.                     {
  2243.                       if( worknode -> fn_CMap )
  2244.                       {
  2245.                         /* Current node contains colormap, this are the colors for the following frames... */
  2246.                         currcm = worknode -> fn_CMap;
  2247.                       }
  2248.                       else
  2249.                       {
  2250.                         if( currcm )
  2251.                         {
  2252.                           /* Copy colormap from previous one... */
  2253.                           if( !(worknode -> fn_CMap = CopyColorMap( cb, currcm )) )
  2254.                           {
  2255.                             /* Can't copy/alloc colormap */
  2256.                             error = ERROR_NO_FREE_STORE;
  2257.                           }
  2258.                         }
  2259.                         else
  2260.                         {
  2261.                           verbose_printf( cb, aid, "scan/load: no colormap, can't copy it\n" );
  2262.                         }
  2263.                       }
  2264.  
  2265.                       worknode = nextnode;
  2266.                     }
  2267.                   }
  2268.                 }
  2269.               }
  2270.             }
  2271.  
  2272.             /* Check for required information */
  2273.             if( error == 0L )
  2274.             {
  2275.               /* bmh information available  ? */
  2276.               if( bmhdprop == NULL )
  2277.               {
  2278.                 verbose_printf( cb, aid, "scan: no bmhd found\n" );
  2279.  
  2280.                 /* BMHD missing */
  2281.                 error = DTERROR_INVALID_DATA;
  2282.               }
  2283.               else
  2284.               {
  2285.                 /* Any frames loaded ? */
  2286.                 if( timestamp == 0UL )
  2287.                 {
  2288.                   /* not enougth frames (at least one required) */
  2289.                   error = DTERROR_NOT_ENOUGH_DATA;
  2290.                 }
  2291.               }
  2292.             }
  2293.  
  2294.             /* Dynamic timing ? */
  2295.             if( (minreltime != maxreltime) && ((aid -> aid_NoDynamicTiming) == FALSE) )
  2296.             {
  2297.               struct FrameNode *worknode,
  2298.                                *nextnode;
  2299.               ULONG             shift = 0UL;    
  2300.               
  2301.               if( minreltime == 0UL )
  2302.               {
  2303.                 shift = 1UL;
  2304.               }
  2305.  
  2306.               if( (aid -> aid_FPS) == 0UL )
  2307.               {
  2308.                 ULONG adaptive;
  2309.  
  2310.                 aid -> aid_FPS = 10UL; /* should be 60 (e.g. 1/60 sec per frame) */
  2311.  
  2312.                 if( GetDTAttrs( o, ADTA_AdaptiveFPS, (&adaptive), TAG_DONE ) == 1UL )
  2313.                 {
  2314.                   if( adaptive )
  2315.                   {
  2316.                     verbose_printf( cb, aid, "animation.datatype uses adaptive playback rate selection\n" );
  2317.  
  2318.                     aid -> aid_FPS = 60UL; /* 1/60 sec per frame */
  2319.                   }
  2320.                 }
  2321.               }
  2322.  
  2323.               verbose_printf( cb, aid, "using dynamic timing, fps = %lu\n", (aid -> aid_FPS) );
  2324.  
  2325.               /* Renumber timestamps */
  2326.               timestamp = 0UL; /* again we count from 0 */
  2327.  
  2328.               worknode = (struct FrameNode *)(aid -> aid_FrameList . mlh_Head);
  2329.  
  2330.               while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  2331.               {
  2332.                 ULONG duration = (worknode -> fn_AH . ah_RelTime) + shift - 1UL;
  2333.  
  2334.                 worknode -> fn_TimeStamp = timestamp;
  2335.                 worknode -> fn_Frame     = timestamp;
  2336.                 worknode -> fn_Duration  = duration;
  2337.  
  2338.                 timestamp += (duration + 1UL);
  2339.  
  2340.                 worknode = nextnode;
  2341.               }
  2342.             }
  2343.  
  2344.             /* Any error ? */
  2345.             if( error == 0L )
  2346.             {
  2347.               /* Alloc bitmap as key bitmap  */
  2348.               if( aid -> aid_KeyBitMap = AllocBitMap( animwidth, animheight, animdepth, (BMF_CLEAR | BMF_MINPLANES), NULL ) )
  2349.               {
  2350.                 struct FrameNode *firstfn = (struct FrameNode *)(aid -> aid_FrameList . mlh_Head); /* short cut to the first FrameNode */
  2351.                 
  2352.                 aid -> aid_CurrFN = firstfn;
  2353.  
  2354.                 if( (firstfn -> fn_BitMap) == NULL )
  2355.                 {
  2356.                   if( !(firstfn -> fn_BitMap = AllocBitMapPooled( cb, (ULONG)(aid -> aid_BMH -> bmh_Width), (ULONG)(aid -> aid_BMH -> bmh_Height), (ULONG)(aid -> aid_BMH -> bmh_Depth), (aid -> aid_FramePool) )) )
  2357.                   {
  2358.                     /* can't alloc first bitmap */
  2359.                     error = ERROR_NO_FREE_STORE;
  2360.                   }
  2361.                 }
  2362.  
  2363.                 if( error == 0L )
  2364.                 {
  2365.                   /* Copy first frame into key bitmap */
  2366.                   CopyBitMap( cb, (firstfn -> fn_BitMap), (aid -> aid_KeyBitMap) );
  2367.  
  2368.                   /* No name chunk ? */
  2369.                   if( nameprop == NULL )
  2370.                   {
  2371.                     STRPTR name;
  2372.  
  2373.                     GetDTAttrs( o, DTA_Name, (&name), TAG_DONE );
  2374.                     SetDTAttrs( o, NULL, NULL, DTA_ObjName, name, TAG_DONE );
  2375.                   }
  2376.  
  2377.                   /* ModeID... */
  2378.                   if( aid -> aid_ModeID )
  2379.                   {
  2380.                     modeid = aid -> aid_ModeID;
  2381.                   }
  2382.                   else
  2383.                   {
  2384.                     /* No mode id ? */
  2385.                     if( modeid == 0UL )
  2386.                     {
  2387.                       /* BUG: Duoes currently not support SUPERHIRES modes */
  2388.                       if( animwidth >= 640UL )
  2389.                       {
  2390.                         if( animheight >= 400 )
  2391.                         {
  2392.                           modeid = HIRESLACE_KEY;
  2393.                         }
  2394.                         else
  2395.                         {
  2396.                           modeid = HIRES_KEY;
  2397.                         }
  2398.                       }
  2399.                       else
  2400.                       {
  2401.                         if( animheight >= 400 )
  2402.                         {
  2403.                           modeid = LORESLACE_KEY;
  2404.                         }
  2405.                         else
  2406.                         {
  2407.                           modeid = LORES_KEY;
  2408.                         }
  2409.                       }
  2410.                     }
  2411.                   }
  2412.  
  2413.                   /* No FPS rate found ? */
  2414.                   if( (aid -> aid_FPS) == 0UL )
  2415.                   {
  2416.                     aid -> aid_FPS = 5UL;
  2417.                   }
  2418.  
  2419.                   /* Attach external sound */
  2420.                   AttachSample( cb, aid );
  2421.  
  2422.                   /* Infos */
  2423.                   verbose_printf( cb, aid, "width %lu height %lu depth %lu frames %lu fps %lu\n",
  2424.                                 animwidth,
  2425.                                 animheight,
  2426.                                 animdepth,
  2427.                                 timestamp,
  2428.                                 (aid -> aid_FPS) );
  2429.  
  2430.                   /* Set misc attributes */
  2431.                   SetDTAttrs( o, NULL, NULL,
  2432.                               DTA_TotalHoriz,       animwidth,
  2433.                               DTA_TotalVert,        animheight,
  2434.                               ADTA_Width,           animwidth,
  2435.                               ADTA_Height,          animheight,
  2436.                               ADTA_Depth,           animdepth,
  2437.                               ADTA_ModeID,          modeid,
  2438.                               ADTA_Frames,          timestamp,
  2439.                               ADTA_FramesPerSecond, (aid -> aid_FPS),
  2440.                               ADTA_KeyFrame,        (aid -> aid_KeyBitMap),
  2441.                               ADTA_Sample,          (firstfn -> fn_Sample),
  2442.                               ADTA_SampleLength,    (firstfn -> fn_SampleLength),
  2443.                               ADTA_Period,          (firstfn -> fn_Period),
  2444.                               ADTA_Volume,          (aid -> aid_Volume),
  2445.                               ADTA_Cycles,          1UL,
  2446.                               TAG_DONE );
  2447.                 }
  2448.               }
  2449.               else
  2450.               {
  2451.                 /* can't alloc key bitmap */
  2452.                 error = ERROR_NO_FREE_STORE;
  2453.               }
  2454.             }
  2455.           }
  2456.           else
  2457.           {
  2458.             /* No iff handle ? - Be sure we got a DTST_RAM sourcetype */
  2459.             if( sourcetype != DTST_RAM )
  2460.             {
  2461.               /* No handle ! */
  2462.               error = ERROR_REQUIRED_ARG_MISSING;
  2463.             }
  2464.           }
  2465.         }
  2466.       }
  2467.       else
  2468.       {
  2469.         /* can't get required attributes from superclass */
  2470.         error = ERROR_OBJECT_WRONG_TYPE;
  2471.       }
  2472.     }
  2473.     else
  2474.     {
  2475.       /* no memory pool */
  2476.       error = ERROR_NO_FREE_STORE;
  2477.     }
  2478.  
  2479.     /* Error codes below 0 are related to the IFFParse.library functions */
  2480.     if( error < 0L )
  2481.     {
  2482.       verbose_printf( cb, aid, "iff error %ld\n", (long)error );
  2483.  
  2484.       /* convert IFFParse error to DOS error */
  2485.       error = ifferr2doserr[ (-error - 1) ];
  2486.     }
  2487.  
  2488.     return( error );
  2489. }
  2490.  
  2491.  
  2492. static
  2493. struct FrameNode *AllocFrameNode( struct ClassBase *cb, APTR pool )
  2494. {
  2495.     struct FrameNode *fn;
  2496.  
  2497.     if( fn = (struct FrameNode *)AllocPooled( pool, (ULONG)sizeof( struct FrameNode ) ) )
  2498.     {
  2499.       memset( fn, 0, sizeof( struct FrameNode ) );
  2500.     }
  2501.  
  2502.     return( fn );
  2503. }
  2504.  
  2505.  
  2506. static
  2507. struct FrameNode *FindFrameNode( struct MinList *fnl, ULONG timestamp )
  2508. {
  2509.     if( fnl )
  2510.     {
  2511.       struct FrameNode *worknode,
  2512.                        *nextnode,
  2513.                        *prevnode;
  2514.  
  2515.       prevnode = worknode = (struct FrameNode *)(fnl -> mlh_Head);
  2516.  
  2517.       while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  2518.       {
  2519.         if( (worknode -> fn_TimeStamp) > timestamp )
  2520.         {
  2521.           return( prevnode );
  2522.         }
  2523.  
  2524.         prevnode = worknode;
  2525.         worknode = nextnode;
  2526.       }
  2527.  
  2528.       if( !IsListEmpty( ((struct List *)fnl) ) )
  2529.       {
  2530.         return( prevnode );
  2531.       }  
  2532.     }
  2533.  
  2534.     return( NULL );
  2535. }
  2536.  
  2537.  
  2538. static
  2539. void FreeFrameNodeResources( struct ClassBase *cb, struct MinList *fnl )
  2540. {
  2541.     if( fnl )
  2542.     {
  2543.       struct FrameNode *worknode,
  2544.                        *nextnode;
  2545.  
  2546.       worknode = (struct FrameNode *)(fnl -> mlh_Head);
  2547.  
  2548.       while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  2549.       {
  2550.         if( worknode -> fn_CMap )
  2551.         {
  2552.           FreeColorMap( (worknode -> fn_CMap) );
  2553.           worknode -> fn_CMap = NULL;
  2554.         }
  2555.  
  2556.         worknode = nextnode;
  2557.       }
  2558.     }
  2559. }
  2560.  
  2561.  
  2562. /* Copy bm1 to bm2 */
  2563. static
  2564. void CopyBitMap( struct ClassBase *cb, struct BitMap *bm1, struct BitMap *bm2 )
  2565. {
  2566.     ULONG  bpr1 = bm1 -> BytesPerRow;
  2567.     ULONG  bpr2 = bm2 -> BytesPerRow;
  2568.  
  2569.     /* Same bitmap layout ? */
  2570.     if( bpr1 == bpr2 )
  2571.     {
  2572.       /* Interleaved BitMap ? */
  2573.       if( ((bm1 -> Planes[ 1 ]) - (bm1 -> Planes[ 0 ])) == (bpr1 / (ULONG)(bm1 -> Depth)) )
  2574.       {
  2575.         ULONG planesize = bpr2 * (ULONG)(bm2 -> Rows);
  2576.  
  2577.         XCopyMem( cb, (bm1 -> Planes[ 0 ]), (bm2 -> Planes[ 0 ]), planesize );
  2578.       }
  2579.       else
  2580.       {
  2581.         ULONG planesize = bpr2 * (ULONG)(bm2 -> Rows);
  2582.         UWORD i;
  2583.  
  2584.         for( i = 0U ; i < (bm2 -> Depth) ; i++ )
  2585.         {
  2586.           XCopyMem( cb, (bm1 -> Planes[ i ]), (bm2 -> Planes[ i ]), planesize );
  2587.         }
  2588.       }
  2589.     }
  2590.     else
  2591.     {
  2592.       register UBYTE *src;
  2593.       register UBYTE *dst;
  2594.       register LONG   r;
  2595.       register LONG   p;
  2596.                ULONG  width = bm1 -> BytesPerRow;
  2597.  
  2598.       /* Interleaved BitMap ? */
  2599.       if( ((bm1 -> Planes[ 1 ]) - (bm1 -> Planes[ 0 ])) == (bpr1 / (ULONG)(bm1 -> Depth)) )
  2600.       {
  2601.         width /= (bm1 -> Depth);
  2602.       }
  2603.  
  2604.       for( p = bm1 -> Depth - 1 ; p >= 0 ; p-- )
  2605.       {
  2606.         src = (BYTE *)bm1 -> Planes[ p ];
  2607.         dst = (BYTE *)bm2 -> Planes[ p ];
  2608.  
  2609.         for( r = bm1 -> Rows - 1 ; r >= 0 ; r-- )
  2610.         {
  2611.           CopyMem( src, dst, width );
  2612.           src += bpr1;
  2613.           dst += bpr2;
  2614.         }
  2615.       }
  2616.     }
  2617. }
  2618.  
  2619.  
  2620. static
  2621. void XCopyMem( struct ClassBase *cb, APTR src, APTR dest, ULONG size )
  2622. {
  2623.     /* Check if we can use the optimized CopyMemQuick */
  2624.     if( (ALIGN_LONG( src ) == src) && (ALIGN_LONG( dest ) == dest) )
  2625.     {
  2626.       register ULONG lsize = size & ~3UL,
  2627.                      cut   = size - lsize; /* remaining bytes (0-3) */
  2628.  
  2629.       CopyMemQuick( src, dest, lsize );
  2630.  
  2631.       if( cut )
  2632.       {
  2633.         src  = ((UBYTE *)src)  + lsize;
  2634.         dest = ((UBYTE *)dest) + lsize;
  2635.  
  2636.         CopyMem( src, dest, cut );
  2637.       }
  2638.     }
  2639.     else
  2640.     {
  2641.       CopyMem( src, dest, size );
  2642.     }
  2643. }
  2644.  
  2645.  
  2646. static
  2647. void ClearBitMap( struct BitMap *bm )
  2648. {
  2649.     if( bm )
  2650.     {
  2651.       ULONG planesize = (ULONG)(bm -> BytesPerRow) * (ULONG)(bm -> Rows);
  2652.       UWORD i;
  2653.  
  2654.       for( i = 0U ; i < (bm -> Depth) ; i++ )
  2655.       {
  2656.         memset( (bm -> Planes[ i ]), 0, (size_t)planesize );
  2657.       }
  2658.     }
  2659. }
  2660.  
  2661.  
  2662. /* XOR Bitmaps op1 ^= op2 */
  2663. static
  2664. void XORBitMaps( struct BitMap *op1, struct BitMap *op2 )
  2665. {
  2666.     if( op1 && op2 )
  2667.     {
  2668.                ULONG  planesize = (ULONG)(op1 -> BytesPerRow) * (ULONG)(op1 -> Rows);
  2669.                ULONG  missing;
  2670.                ULONG  i;
  2671.       register ULONG  j;
  2672.       register ULONG *op1p, /* op1 planes */
  2673.                      *op2p; /* op2 planes */
  2674.  
  2675.       planesize = planesize / sizeof( ULONG ); /* op1p and op2p are ULONGs, not BYTES... */
  2676.       missing   = planesize % sizeof( ULONG ); /* missing bytes */
  2677.  
  2678.       for( i = 0U ; i < (op1 -> Depth) ; i++ )
  2679.       {
  2680.         j = planesize;
  2681.  
  2682.         op1p = (ULONG *)(op1 -> Planes[ i ]);
  2683.         op2p = (ULONG *)(op2 -> Planes[ i ]);
  2684.  
  2685.         while( j-- )
  2686.         {
  2687.           *op1p++ ^= *op2p++;
  2688.         }
  2689.  
  2690.         if( missing )
  2691.         {
  2692.           register UBYTE *op1px = (UBYTE *)op1p;
  2693.           register UBYTE *op2px = (UBYTE *)op2p;
  2694.  
  2695.           j = missing;
  2696.  
  2697.           while( j-- )
  2698.           {
  2699.             *op1px++ ^= *op2px++;
  2700.           }
  2701.         }
  2702.       }
  2703.     }
  2704. }
  2705.  
  2706.  
  2707. static
  2708. struct BitMap *AllocBitMapPooled( struct ClassBase *cb, ULONG width, ULONG height, ULONG depth, APTR pool )
  2709. {
  2710.     struct BitMap *bm;
  2711.     ULONG          planesize,
  2712.                    moredepthsize,
  2713.                    size;
  2714.  
  2715.     planesize       = (ULONG)RASSIZE( ((width + 63UL) & ~63UL), height );
  2716.     moredepthsize   = (depth > 8UL)?((depth - 8UL) * sizeof( PLANEPTR )):(0UL);
  2717.     size            = ((ULONG)sizeof( struct BitMap )) + moredepthsize + (planesize * depth) + 31UL;
  2718.  
  2719.     if( bm = (struct BitMap *)AllocVecPooled( cb, pool, size ) )
  2720.     {
  2721.       UWORD    pl;
  2722.       PLANEPTR plane;
  2723.  
  2724.       InitBitMap( bm, depth, width, height );
  2725.  
  2726.       plane = ALIGN_QUADLONG( (PLANEPTR)(bm + 1) ); /* First plane follows struct BitMap */
  2727.  
  2728.       /* Set up plane data */
  2729.       pl = 0U;
  2730.  
  2731.       /* Set up plane ptrs */
  2732.       while( pl < depth )
  2733.       {
  2734.         bm -> Planes[ pl ] = plane;
  2735.  
  2736.         plane = ALIGN_QUADLONG( (PLANEPTR)(((UBYTE *)plane) + planesize) );
  2737.         pl++;
  2738.       }
  2739.  
  2740.       /* Clear the remaining plane ptrs (up to 8 planes) */
  2741.       while( pl < 8U )
  2742.       {
  2743.         bm -> Planes[ pl ] = NULL;
  2744.  
  2745.         pl++;
  2746.       }
  2747.     }
  2748.  
  2749.     return( bm );
  2750. }
  2751.  
  2752.  
  2753. static
  2754. BOOL CMAP2Object( struct ClassBase *cb, Object *o, UBYTE *rgb, ULONG rgbsize )
  2755. {
  2756.     struct ColorRegister *acm;
  2757.     ULONG                *acregs;
  2758.     ULONG                 nc;
  2759.  
  2760.     /* file has this many colors (e.g. each color has one byte per R,B,G-gun) */
  2761.     nc = rgbsize / 3UL;
  2762.  
  2763.     SetDTAttrs( o, NULL, NULL, ADTA_NumColors, nc, TAG_DONE );
  2764.  
  2765.     /* Get color context */
  2766.     if( GetDTAttrs( o,
  2767.                     ADTA_ColorRegisters, (&acm),
  2768.                     ADTA_CRegs,          (&acregs),
  2769.                     ADTA_NumColors,      (&nc),
  2770.                     TAG_DONE ) == 3UL )
  2771.     {
  2772.       /* All valid ? */
  2773.       if( acm && acregs && nc )
  2774.       {
  2775.         ULONG i;
  2776.  
  2777.         for( i = 0UL ; i < nc ; i++, acm++ )
  2778.         {
  2779.           acm -> red   =  *rgb++;
  2780.           acm -> green =  *rgb++;
  2781.           acm -> blue  =  *rgb++;
  2782.  
  2783.           /* Replicate the color information.
  2784.            * This surrounds an OS bug which uses the low-oreder bytes of the 32-bit colors
  2785.            * instead of the high order ones
  2786.            */
  2787.           acregs[ ((i * 3) + 0) ] = ((ULONG)(acm -> red))   * 0x01010101UL;
  2788.           acregs[ ((i * 3) + 1) ] = ((ULONG)(acm -> green)) * 0x01010101UL;
  2789.           acregs[ ((i * 3) + 2) ] = ((ULONG)(acm -> blue))  * 0x01010101UL;
  2790.         }
  2791.  
  2792.         return( TRUE );
  2793.       }
  2794.     }
  2795.  
  2796.     return( FALSE );
  2797. }
  2798.  
  2799.  
  2800. static
  2801. struct ColorMap *CMAP2ColorMap( struct ClassBase *cb, struct AnimInstData *aid, UBYTE *rgb, ULONG rgbsize )
  2802. {
  2803.     struct ColorMap *cm;
  2804.     ULONG            a_nc   = (1UL << (ULONG)(aid -> aid_BMH -> bmh_Depth)); /* Number of colors in animation */
  2805.     ULONG            rgb_nc = rgbsize / 3UL;                                 /* Number of colors in CMAP      */
  2806.  
  2807.     /* Get a colormap which hold all colors */
  2808.     if( cm = GetColorMap( (long)MAX( a_nc, rgb_nc ) ) )
  2809.     {
  2810.       ULONG i,
  2811.             r, g, b;
  2812.  
  2813.       for( i = 0UL ; i < rgb_nc ; i++ )
  2814.       {
  2815.         r = *rgb++;
  2816.         g = *rgb++;
  2817.         b = *rgb++;
  2818.  
  2819.         /* Replicate color information (see CMAP2Object for details) and store them into colormap */
  2820.         SetRGB32CM( cm, i, (r * 0x01010101UL), (g * 0x01010101UL), (b * 0x01010101UL) );
  2821.       }
  2822.  
  2823.       /* BUG: the remaining entries should be filled with colors from the last colormap */
  2824.       for( ; i < a_nc ; i++ )
  2825.       {
  2826.         SetRGB32CM( cm, i, 0UL, 0UL, 0UL ); /* fill remaining entries with black */
  2827.       }
  2828.     }
  2829.  
  2830.     return( cm );
  2831. }
  2832.  
  2833.  
  2834. static
  2835. struct ColorMap *CopyColorMap( struct ClassBase *cb, struct ColorMap *src )
  2836. {
  2837.     struct ColorMap *dest = NULL;
  2838.  
  2839.     if( src )
  2840.     {
  2841.       ULONG *ctable;
  2842.  
  2843.       if( ctable = (ULONG *)AllocVec( ((ULONG)(src -> Count) * sizeof( ULONG ) * 3UL), MEMF_PUBLIC ) )
  2844.       {
  2845.         if( dest = GetColorMap( (long)(src -> Count) ) )
  2846.         {
  2847.           ULONG i;
  2848.  
  2849.           GetRGB32( src, 0UL, (ULONG)(src -> Count), ctable );
  2850.  
  2851.           for( i = 0UL ; i < (src -> Count) ; i++ )
  2852.           {
  2853.             SetRGB32CM( dest, i, ctable[ ((i * 3) + 0) ], ctable[ ((i * 3) + 1) ], ctable[ ((i * 3) + 2) ] );
  2854.           }
  2855.         }
  2856.  
  2857.         FreeVec( ctable );
  2858.       }
  2859.     }
  2860.  
  2861.     return( dest );
  2862. }
  2863.  
  2864.  
  2865. /*****************************************************************************/
  2866.  
  2867. #define DEBUG_POOLS 1
  2868.  
  2869. #ifndef DEBUG_POOLS
  2870. static
  2871. APTR AllocVecPooled( struct ClassBase *cb, APTR pool, ULONG memsize )
  2872. {
  2873.     ULONG *memory = NULL;
  2874.  
  2875.     if( pool && memsize )
  2876.     {
  2877.       memsize += (ULONG)sizeof( ULONG );
  2878.  
  2879.       if( memory = (ULONG *)AllocPooled( pool, memsize ) )
  2880.       {
  2881.         (*memory) = memsize;
  2882.  
  2883.         memory++;
  2884.       }
  2885.     }
  2886.  
  2887.     return( (APTR)memory );
  2888. }
  2889.  
  2890.  
  2891. static
  2892. void FreeVecPooled( struct ClassBase *cb, APTR pool, APTR mem )
  2893. {
  2894.     if( pool && mem )
  2895.     {
  2896.       ULONG *memory;
  2897.  
  2898.       memory = (ULONG *)mem;
  2899.  
  2900.       memory--;
  2901.  
  2902.       FreePooled( pool, memory, (*memory) );
  2903.     }
  2904. }
  2905. #else
  2906. #define MY_MAGIC_MEMID (0xD0ADEAD0UL)
  2907.  
  2908. static
  2909. APTR AllocVecPooled( struct ClassBase *cb, APTR pool, ULONG memsize )
  2910. {
  2911.     ULONG *memory = NULL;
  2912.  
  2913.     if( pool && memsize )
  2914.     {
  2915.       memsize += (ULONG)sizeof( ULONG );
  2916.       memsize += (ULONG)sizeof( APTR );
  2917.  
  2918.       if( memory = (ULONG *)AllocPooled( pool, memsize ) )
  2919.       {
  2920.         (*memory) = memsize;
  2921.         memory++;
  2922.  
  2923.         (*memory) = (ULONG)pool;
  2924.         memory++;
  2925.  
  2926.         (*memory) = MY_MAGIC_MEMID;
  2927.         memory++;
  2928.       }
  2929.     }
  2930.  
  2931.     return( (APTR)memory );
  2932. }
  2933.  
  2934.  
  2935. static
  2936. void FreeVecPooled( struct ClassBase *cb, APTR pool, APTR mem )
  2937. {
  2938.     if( pool && mem )
  2939.     {
  2940.       ULONG *memory;
  2941.  
  2942.       memory = (ULONG *)mem;
  2943.  
  2944.       memory--;
  2945.  
  2946.       if( *memory != MY_MAGIC_MEMID )
  2947.       {
  2948.         D( kprintf( "wrong mem id\n" ) );
  2949.         return;
  2950.       }
  2951.  
  2952.       memory--;
  2953.  
  2954.       if( *memory != (ULONG)pool )
  2955.       {
  2956.         D( kprintf( "wrong pool %lx %lx\n", pool, *memory ) );
  2957.         return;
  2958.       }
  2959.  
  2960.       memory--;
  2961.  
  2962.       FreePooled( pool, memory, (*memory) );
  2963.     }
  2964. }
  2965. #endif /* DEBUG_POOLS */
  2966.  
  2967.  
  2968. static
  2969. LONG DrawDLTA( struct ClassBase *cb, struct AnimInstData *aid, struct BitMap *prevbm, struct BitMap *bm, struct AnimHeader *ah, UBYTE *dlta, ULONG dltasize )
  2970. {
  2971.     LONG error = 0L;
  2972.  
  2973.     if( bm && ah && dlta && dltasize )
  2974.     {
  2975.       struct BitMap       *unpackbm = bm,
  2976.                           *tempbm   = NULL;
  2977.       struct BitMapHeader *bmh      = aid -> aid_BMH;
  2978.       BOOL                 DoXOR;
  2979.  
  2980.       /* Handle acmpILBM, acmpXORILBM and acmpAnimJ explicitly */
  2981.       switch( ah -> ah_Operation )
  2982.       {
  2983.         case acmpILBM:    /*  0  */
  2984.         {
  2985.             /* unpack ILBM BODY */
  2986.             return( LoadILBMBody( cb, unpackbm, bmh, dlta, dltasize ) );
  2987.         }
  2988.  
  2989.         case acmpXORILBM: /*  1  */
  2990.         {
  2991.             error_printf( cb, aid, "\adlta: acmpXORILBM disabled, call author immediately\n" );
  2992.             return( ERROR_NOT_IMPLEMENTED );
  2993.         }
  2994.  
  2995.         case acmpAnimJ:   /* 'J' */
  2996.         {
  2997.             /* unpack ANIM-J  */
  2998.             return( unpackanimjdelta( cb, dlta, dltasize, prevbm, bm ) );
  2999.         }
  3000.       }
  3001.  
  3002.       /* XOR ? */
  3003.       DoXOR = ((ah -> ah_Flags) & ahfXOR);
  3004.  
  3005.       if( !DoXOR )
  3006.       {
  3007.         if( (aid -> aid_NoDPaintBrushPatch) == FALSE )
  3008.         {
  3009.           /* DPaint anim brush (compatibility hack) */
  3010.           if( ((ah -> ah_Operation) == acmpByteDelta) && ((ah -> ah_Interleave) == 1U) )
  3011.           {
  3012.             DoXOR = TRUE;
  3013.           }
  3014.         }
  3015.       }
  3016.  
  3017.       /* Prepare XOR (see below) */
  3018.       if( DoXOR && prevbm )
  3019.       {
  3020.         if( prevbm == bm )
  3021.         {
  3022.           if( !(tempbm = AllocBitMapPooled( cb, (ULONG)(aid -> aid_BMH -> bmh_Width), (ULONG)(aid -> aid_BMH -> bmh_Height), (ULONG)(aid -> aid_BMH -> bmh_Depth), (aid -> aid_FramePool) )) )
  3023.           {
  3024.             return( ERROR_NO_FREE_STORE );
  3025.           }
  3026.  
  3027.           unpackbm = prevbm = tempbm;
  3028.         }
  3029.  
  3030.         ClearBitMap( unpackbm );
  3031.       }
  3032.       else
  3033.       {
  3034.         if( prevbm )
  3035.         {
  3036.           if( prevbm != bm )
  3037.           {
  3038.             CopyBitMap( cb, prevbm, bm );
  3039.           }
  3040.         }
  3041.         else
  3042.         {
  3043.           ClearBitMap( bm );
  3044.         }
  3045.       }
  3046.  
  3047.       /* dispatch compression type, second attempt */
  3048.       switch( ah -> ah_Operation )
  3049.       {
  3050.         /* acmpILBM, acmpXORILBM and acmpAnimJ have been processed above */
  3051.  
  3052.         case acmpLongDelta:         /* 2 */
  3053.         {
  3054.             error = unpacklongdelta( unpackbm, dlta, dltasize );
  3055.         }
  3056.             break;
  3057.  
  3058.         case acmpShortDelta:        /* 3 */
  3059.         {
  3060.             error = unpackshortdelta( unpackbm, dlta, dltasize );
  3061.         }
  3062.             break;
  3063.  
  3064.         case acmpDelta:             /*  4 */
  3065.         {
  3066. #ifdef COMMENTED_OUT
  3067.             if( (ah -> ah_Flags) & ahfLongData )
  3068.             {
  3069.               error = unpackanim4longdelta( unpackbm, dlta, dltasize, (ah -> ah_Flags) );
  3070.             }
  3071.             else
  3072.             {
  3073.               error = unpackanim4worddelta( unpackbm, dlta, dltasize, (ah -> ah_Flags) );
  3074.             }
  3075. #else
  3076.             error_printf( cb, aid, "\adlta: acmpDelta disabled, call author (gisburn@w-specht.rhein-ruhr.de)\n"
  3077.                                    "immediately. If you are this FIRST user who send me a VALID IFF ANIM-4 compressed animation\n"
  3078.                                    "you'll get $10 US-Dollar !!\n THIS IS NO JOKE !!\n" );
  3079.             error = ERROR_NOT_IMPLEMENTED;
  3080. #endif /* COMMENTED_OUT */
  3081.         }
  3082.             break;
  3083.  
  3084.         case acmpByteDelta:         /* 5 */
  3085.         case acmpStereoByteDelta:   /* 6 */
  3086.         {
  3087.             error = unpackbytedelta( unpackbm, dlta, dltasize );
  3088.         }
  3089.             break;
  3090.  
  3091.         case acmpAnim7:             /* 7 */
  3092.         {
  3093.             if( (ah -> ah_Flags) & ahfLongData )
  3094.             {
  3095.               error = unpackanim7longdelta( unpackbm, dlta, dltasize );
  3096.             }
  3097.             else
  3098.             {
  3099.               error = unpackanim7worddelta( unpackbm, dlta, dltasize );
  3100.             }
  3101.         }
  3102.             break;
  3103.  
  3104.         case acmpAnim8:             /* 8 */
  3105.         {
  3106.             if( (ah -> ah_Flags) & ahfLongData )
  3107.             {
  3108.               error = unpackanim8longdelta( unpackbm, dlta, dltasize );
  3109.             }
  3110.             else
  3111.             {
  3112.               error = unpackanim8worddelta( unpackbm, dlta, dltasize );
  3113.             }
  3114.         }
  3115.             break;
  3116.  
  3117.         default:                    /* 'l' */
  3118.         {
  3119.             error_printf( cb, aid, "\adlta: anim compression %ld not implemented yet\n", (long)(ah -> ah_Operation) );
  3120.             error = ERROR_NOT_IMPLEMENTED;
  3121.         }
  3122.             break;
  3123.       }
  3124.  
  3125.       /* Handle XOR (see above) */
  3126.       if( DoXOR && prevbm )
  3127.       {
  3128.         XORBitMaps( bm, prevbm );
  3129.       }
  3130.  
  3131.       if( tempbm )
  3132.       {
  3133.         FreeVecPooled( cb, (aid -> aid_FramePool), tempbm );
  3134.       }
  3135.     }
  3136.  
  3137.     return( error );
  3138. }
  3139.  
  3140.  
  3141. static
  3142. void DumpAnimHeader( struct ClassBase *cb, struct AnimInstData *aid, ULONG ti, struct AnimHeader *anhd )
  3143. {
  3144.     if( anhd )
  3145.     {
  3146.       verbose_printf( cb, aid, "%4lu: ", ti );
  3147.  
  3148.       switch( anhd -> ah_Operation )
  3149.       {
  3150.         case acmpILBM:              verbose_printf( cb, aid, "Operation ILBM" );                  break;
  3151.         case acmpXORILBM:           verbose_printf( cb, aid, "Operation XORILBM" );               break;
  3152.         case acmpLongDelta:         verbose_printf( cb, aid, "Operation LongDelta" );             break;
  3153.         case acmpShortDelta:        verbose_printf( cb, aid, "Operation ShortDelta" );            break;
  3154.         case acmpDelta:             verbose_printf( cb, aid, "Operation Delta" );                 break;
  3155.         case acmpByteDelta:         verbose_printf( cb, aid, "Operation ByteDelta" );             break;
  3156.         case acmpStereoByteDelta:   verbose_printf( cb, aid, "Operation StereoByteDelta" );       break;
  3157.         case acmpAnim7:             verbose_printf( cb, aid, "Operation Anim7" );                 break;
  3158.         case acmpAnim8:             verbose_printf( cb, aid, "Operation Anim8" );                 break;
  3159.         case acmpAnimJ:             verbose_printf( cb, aid, "Operation AnimJ" );                 break;
  3160.         default:                    verbose_printf( cb, aid, "Operation <unknown compression>" ); break;
  3161.       }
  3162.  
  3163.       verbose_printf( cb, aid, " AbsTime %3lu RelTime %3lu Interleave %3lu", (anhd -> ah_AbsTime), (anhd -> ah_RelTime), (ULONG)(anhd -> ah_Interleave) );
  3164.  
  3165.       if( (anhd -> ah_Flags) & ahfLongData          ) verbose_printf( cb, aid, " LongData"          );
  3166.       if( (anhd -> ah_Flags) & ahfXOR               ) verbose_printf( cb, aid, " XOR"               );
  3167.       if( (anhd -> ah_Flags) & ahfOneInfoList       ) verbose_printf( cb, aid, " OneInfoList"       );
  3168.       if( (anhd -> ah_Flags) & ahfRLC               ) verbose_printf( cb, aid, " RLC"               );
  3169.       if( (anhd -> ah_Flags) & ahfVertical          ) verbose_printf( cb, aid, " Vertical"          );
  3170.       if( (anhd -> ah_Flags) & ahfLongInfoOffsets   ) verbose_printf( cb, aid, " LongInfoOffsets"   );
  3171.  
  3172.       verbose_printf( cb, aid, "\n" );
  3173.  
  3174.       if( (aid -> aid_NoDPaintBrushPatch) == FALSE )
  3175.       {
  3176.         /* DPaint anim brush (compatibility hack) */
  3177.         if( (anhd -> ah_Operation == acmpByteDelta) && ((anhd -> ah_Interleave) == 1U) && (!((anhd -> ah_Flags) & ahfXOR)) )
  3178.         {
  3179.           verbose_printf( cb, aid, "Assuming XOR mode for this frame (DPaint brush patch, see docs)\n" );
  3180.         }
  3181.       }
  3182.     }
  3183. }
  3184.  
  3185.  
  3186. static
  3187. struct FrameNode *GetPrevFrameNode( struct FrameNode *currfn, ULONG interleave )
  3188. {
  3189.     struct FrameNode *worknode,
  3190.                      *prevnode;
  3191.  
  3192.     /* Get previous frame */
  3193.     worknode = currfn;
  3194.  
  3195.     while( prevnode = (struct FrameNode *)(worknode -> fn_Node . mln_Pred) )
  3196.     {
  3197.       if( (interleave-- == 0U) || ((prevnode -> fn_Node . mln_Pred) == NULL) )
  3198.       {
  3199.         break;
  3200.       }
  3201.  
  3202.       worknode = prevnode;
  3203.     }
  3204.  
  3205.     return( worknode );
  3206. }
  3207.  
  3208.  
  3209. static
  3210. void OpenLogfile( struct ClassBase *cb, struct AnimInstData *aid )
  3211. {
  3212.     if( (aid -> aid_VerboseOutput) == NULL )
  3213.     {
  3214.       STRPTR confile;
  3215.  
  3216.       if( confile = (STRPTR)AllocVec( (((aid -> aid_ProjectName)?(strlen( (aid -> aid_ProjectName) )):(0UL)) + 100UL), MEMF_PUBLIC ) )
  3217.       {
  3218.         mysprintf( cb, confile, "CON:////Anim DataType %s/auto/wait/close/inactive",
  3219.                    ((aid -> aid_ProjectName)?(FilePart( (aid -> aid_ProjectName) )):(NULL)) );
  3220.  
  3221.         aid -> aid_VerboseOutput = Open( confile, MODE_READWRITE );
  3222.  
  3223.         FreeVec( confile );
  3224.       }
  3225.     }
  3226. }
  3227.  
  3228.  
  3229. static
  3230. void mysprintf( struct ClassBase *cb, STRPTR buffer, STRPTR fmt, ... )
  3231. {
  3232.     APTR args;
  3233.  
  3234.     args = (APTR)((&fmt) + 1);
  3235.  
  3236.     RawDoFmt( fmt, args, (void (*))"\x16\xc0\x4e\x75", buffer );
  3237. }
  3238.  
  3239.  
  3240. static
  3241. void error_printf( struct ClassBase *cb, struct AnimInstData *aid, STRPTR format, ... )
  3242. {
  3243.     OpenLogfile( cb, aid );
  3244.  
  3245.     if( aid -> aid_VerboseOutput )
  3246.     {
  3247.       VFPrintf( (aid -> aid_VerboseOutput), format, (APTR)((&format) + 1) );
  3248.     }
  3249. }
  3250.  
  3251.  
  3252. static
  3253. void verbose_printf( struct ClassBase *cb, struct AnimInstData *aid, STRPTR format, ... )
  3254. {
  3255.     if( aid -> aid_VerboseOutput )
  3256.     {
  3257.       VFPrintf( (aid -> aid_VerboseOutput), format, (APTR)((&format) + 1) );
  3258.     }
  3259. }
  3260.  
  3261.  
  3262. static
  3263. void AttachSample( struct ClassBase *cb, struct AnimInstData *aid )
  3264. {
  3265.     if( aid -> aid_Sample )
  3266.     {
  3267.       struct FrameNode *worknode,
  3268.                        *nextnode;
  3269.  
  3270.       ULONG             period          = aid -> aid_Period;
  3271.       ULONG             samplesperframe;
  3272.       BYTE             *sample          = aid -> aid_Sample;
  3273.  
  3274.       samplesperframe = (((SysBase -> ex_EClockFrequency) * 10UL) / (period * (aid -> aid_FPS) * 2UL));
  3275.  
  3276.       if( aid -> aid_SamplesPerFrame )
  3277.       {
  3278.         period = (period * samplesperframe) / (aid -> aid_SamplesPerFrame);
  3279.  
  3280.         samplesperframe = aid -> aid_SamplesPerFrame;
  3281.  
  3282.         verbose_printf( cb, aid, "period corrected from %lu to %lu to match spf=%lu with fps=%lu\n",
  3283.                         (aid -> aid_Period), period, samplesperframe, (aid -> aid_FPS) );
  3284.       }
  3285.  
  3286.       verbose_printf( cb, aid, "Attching samples (sysclock %lu period %lu fps %lu length %lu samplesperframe %lu)...\n",
  3287.                       (SysBase -> ex_EClockFrequency), period, (aid -> aid_FPS), (aid -> aid_SampleLength), samplesperframe );
  3288.  
  3289.       worknode = (struct FrameNode *)(aid -> aid_FrameList . mlh_Head);
  3290.  
  3291.       while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  3292.       {
  3293.         worknode -> fn_Sample       = sample;
  3294.         worknode -> fn_SampleLength = samplesperframe * ((worknode -> fn_Duration) + 1UL);
  3295.         worknode -> fn_Period       = period;
  3296.  
  3297.         sample += (samplesperframe * ((worknode -> fn_Duration) + 1UL));
  3298.  
  3299.         /* End of sample reached ? */
  3300.         if( (ULONG)(sample - (aid -> aid_Sample)) > (aid -> aid_SampleLength) )
  3301.         {
  3302.           /* Cut last size of sample to fit */
  3303.           worknode -> fn_SampleLength -= (ULONG)(sample - (aid -> aid_Sample));
  3304.  
  3305.           break;
  3306.         }
  3307.  
  3308.         worknode = nextnode;
  3309.       }
  3310.     }
  3311. }
  3312.  
  3313.  
  3314. static
  3315. ULONG SaveIFFAnim( struct ClassBase *cb, struct IClass *cl, Object *o, struct dtWrite *dtw )
  3316. {
  3317.     ULONG retval = 0UL;
  3318.     LONG  error  = 0L;
  3319.  
  3320.     /* A NULL file handle is a nop (GMultiView uses this to test if a datatype supports RAW writing) */
  3321.     if( dtw -> dtw_FileHandle )
  3322.     {
  3323.       struct AnimInstData *aid = (struct AnimInstData *)INST_DATA( cl, o );
  3324.  
  3325.       struct BitMapHeader *bmh;
  3326.       ULONG                modeid;
  3327.       ULONG               *cregs;
  3328.       ULONG                numcolors;
  3329.       ULONG                startframe = 0UL,
  3330.                            numframes  = 0UL,
  3331.                            framestep  = 1UL;
  3332.       ULONG                fps = 0UL;
  3333.       struct BitMap       *keyframe;
  3334.       ULONG                animwidth,
  3335.                            animheight,
  3336.                            animdepth;
  3337.  
  3338.       if( GetDTAttrs( o, ADTA_BitMapHeader,     (&bmh),
  3339.                          ADTA_ModeID,           (&modeid),
  3340.                          ADTA_CRegs,            (&cregs),
  3341.                          ADTA_NumColors,        (&numcolors),
  3342.                          ADTA_Width,            (&animwidth),
  3343.                          ADTA_Height,           (&animheight),
  3344.                          ADTA_Depth,            (&animdepth),
  3345.                          ADTA_Frame,            (&startframe),
  3346.                          ADTA_Frames,           (&numframes),
  3347.                          ADTA_FramesPerSecond,  (&fps),
  3348.                          ADTA_KeyFrame,         (&keyframe),
  3349.                          TAG_DONE ) == 11UL )
  3350.       {
  3351.         struct TagItem     *tstate,
  3352.                            *ti;
  3353.         struct AnimContext *ac;
  3354.         struct IFFHandle   *iff;
  3355.         struct BitMapHeader xbmh   = *bmh;
  3356.         BOOL                planar       = MAKEBOOL( GetBitMapAttr( keyframe, BMA_FLAGS ) & BMF_STANDARD );
  3357.         BOOL                interleaved  = MAKEBOOL( GetBitMapAttr( keyframe, BMA_FLAGS ) & BMF_INTERLEAVED );
  3358.  
  3359.         if( planar && (!interleaved) )
  3360.         {
  3361.           xbmh . bmh_Compression = cmpNone; /* Currently we only write an uncompressed key frame */
  3362.  
  3363.           numframes -= startframe;
  3364.  
  3365.           tstate = dtw -> dtw_AttrList;
  3366.  
  3367.           while( ti = NextTagItem( (&tstate) ) )
  3368.           {
  3369.             switch( ti -> ti_Tag )
  3370.             {
  3371.               case ADTA_Frame:            startframe = ti -> ti_Data; break;
  3372.               case ADTA_Frames:           numframes  = ti -> ti_Data; break;
  3373.               case ADTA_FrameIncrement:   framestep  = ti -> ti_Data; break;
  3374.             }
  3375.           }
  3376.  
  3377.           if( framestep == 0UL ) framestep = 1UL;
  3378.  
  3379.           verbose_printf( cb, aid, "saving iff anim %lu %lu %lu\n", startframe, numframes, framestep );
  3380.  
  3381.           if( numframes )
  3382.           {
  3383.             if( ac = CreateAnimContext( cb, animwidth, animheight, animdepth ) )
  3384.             {
  3385.               if( iff = CreateDOSIFFHandle( cb, (dtw -> dtw_FileHandle) ) )
  3386.               {
  3387.                 if( !(error = StartIFFAnim3( cb, aid, iff, ac, (&xbmh), modeid, cregs, numcolors, numframes, fps, keyframe )) )
  3388.                 {
  3389.                   struct adtFrame  alf;
  3390.                   ULONG            timestamp,
  3391.                                   *cmap_cregs = NULL;
  3392.  
  3393.                   /* Start scan through animation */
  3394.                   for( timestamp = startframe ; numframes > 0UL ; timestamp += framestep, numframes-- )
  3395.                   {
  3396.                     /* On error break */
  3397.                     if( error )
  3398.                     {
  3399.                       break;
  3400.                     }
  3401.  
  3402.                     /* Check for CTRL_D signal... */
  3403.                     if( SetSignal( 0UL, 0UL ) & SIGBREAKF_CTRL_D )
  3404.                     {
  3405.                       error = ERROR_BREAK;
  3406.  
  3407.                       break;
  3408.                     }
  3409.  
  3410.                     /* reset method msg */
  3411.                     memset( (void *)(&alf), 0, sizeof( struct adtFrame ) );
  3412.  
  3413.                     /* load frame */
  3414.                     alf . MethodID = ADTM_LOADFRAME;
  3415.                     alf . alf_TimeStamp = timestamp;
  3416.                     alf . alf_Frame     = timestamp;
  3417.  
  3418.                     if( DoMethodA( o, (Msg)(&alf) ) == 0UL )
  3419.                     {
  3420.                       error = IoErr();
  3421.  
  3422.                       if( error != ERROR_OBJECT_NOT_FOUND )
  3423.                       {
  3424.                         break;
  3425.                       }
  3426.                     }
  3427.                     else
  3428.                     {
  3429.                       /* print frame contents */
  3430.                       verbose_printf( cb, aid, "frame: timestamp %lu frame %lu duration %lu bitmap %lx cmap %lx sample %lx len %lu period %lu\n",
  3431.                               timestamp,
  3432.                               (alf . alf_Frame),
  3433.                               (alf . alf_Duration),
  3434.                               (alf . alf_BitMap),
  3435.                               (alf . alf_CMap),
  3436.                               (alf . alf_Sample),
  3437.                               (alf . alf_SampleLength),
  3438.                               (alf . alf_Period) );
  3439.  
  3440.                       if( alf . alf_CMap )
  3441.                       {
  3442.                         if( cmap_cregs = (ULONG *)AllocVec( (((sizeof( ULONG ) * 3UL) + 1UL) * numcolors), MEMF_PUBLIC ) )
  3443.                         {
  3444.                           GetRGB32( (alf . alf_CMap), 0UL, numcolors, cmap_cregs );
  3445.                         }
  3446.                         else
  3447.                         {
  3448.                           error_printf( cb, aid, "can't alloc dynamic palette buffer\n" );
  3449.                           error = ERROR_NO_FREE_STORE;
  3450.                         }
  3451.                       }
  3452.  
  3453.                       if( alf . alf_BitMap )
  3454.                       {
  3455.                         if( error = WriteIFFAnim3( cb, iff, ac, ((timestamp * 60UL) / fps), (60UL / fps), (&xbmh), cmap_cregs, numcolors, (alf . alf_BitMap) ) )
  3456.                         {
  3457.                           error_printf( cb, aid, "error while writing IFF ANIM-3, aborted\n" );
  3458.                         }
  3459.                       }
  3460.  
  3461.                       if( cmap_cregs )
  3462.                       {
  3463.                         FreeVec( cmap_cregs );
  3464.                         cmap_cregs = NULL;
  3465.                       }
  3466.                     }
  3467.  
  3468.                     alf . MethodID = ADTM_UNLOADFRAME;
  3469.                     DoMethodA( o, (Msg)(&alf) );
  3470.                   }
  3471.  
  3472.                   EndIFFAnim3( cb, aid, iff );
  3473.  
  3474.                   if( error == 0L )
  3475.                   {
  3476.                     retval = 1UL; /* success ! */
  3477.                   }
  3478.                 }
  3479.  
  3480.                 FreeIFF( iff );
  3481.               }
  3482.               else
  3483.               {
  3484.                 error = IoErr();
  3485.               }
  3486.  
  3487.               DeleteAnimContext( cb, ac );
  3488.             }
  3489.             else
  3490.             {
  3491.               /* Can't alloc animcontext */
  3492.               error = ERROR_NO_FREE_STORE;
  3493.             }
  3494.           }
  3495.         }  
  3496.         else
  3497.         {
  3498.           /* Does not support non-planar or planar interleaved bitmaps */
  3499.           error = ERROR_NOT_IMPLEMENTED;
  3500.         }
  3501.       }
  3502.       else
  3503.       {
  3504.         error_printf( cb, aid, "not enougth attributes\n" );
  3505.       }
  3506.     }
  3507.  
  3508.     /* Error codes below 0 are related to the IFFParse.library functions */
  3509.     if( error < 0L )
  3510.     {
  3511.       /* convert IFFParse error to DOS error */
  3512.       error = ifferr2doserr[ (-error - 1) ];
  3513.     }
  3514.  
  3515.     SetIoErr( error );
  3516.  
  3517.     return( retval );
  3518. }
  3519.  
  3520.  
  3521. static
  3522. struct IFFHandle *CreateDOSIFFHandle( struct ClassBase *cb, BPTR fh )
  3523. {
  3524.     struct IFFHandle *iff;
  3525.  
  3526.     if( iff = AllocIFF() )
  3527.     {
  3528.       iff -> iff_Stream = (ULONG)fh;
  3529.  
  3530.       InitIFFasDOS( iff );
  3531.     }
  3532.  
  3533.     return( iff );
  3534. }
  3535.  
  3536.  
  3537. static
  3538. LONG StartIFFAnim3( struct ClassBase *cb, struct AnimInstData *aid, struct IFFHandle *iff, struct AnimContext *ac, struct BitMapHeader *bmh, ULONG modeid, ULONG *cregs, ULONG numcolors, ULONG numframes, ULONG fps, struct BitMap *bm )
  3539. {
  3540.     LONG error;
  3541.  
  3542.     if( !(error = OpenIFF( iff, IFFF_WRITE )) )
  3543.     {
  3544.       for( ;; ) /* not a loop, used as a jump table */
  3545.       {
  3546.         if( error = PushChunk( iff, ID_ANIM, ID_FORM, IFFSIZE_UNKNOWN ) )
  3547.           break;
  3548.  
  3549.         /* write initial FORM ILBM */
  3550.         {
  3551.           if( error = PushChunk( iff, ID_ILBM, ID_FORM, IFFSIZE_UNKNOWN ) )
  3552.             break;
  3553.  
  3554.           /* write ILBM BMHD (BitMapHeader) */
  3555.           {
  3556.             if( error = PushChunk( iff, 0UL, ID_BMHD, IFFSIZE_UNKNOWN ) )
  3557.               break;
  3558.  
  3559.             if( WriteChunkBytes( iff, (APTR)bmh, sizeof( struct BitMapHeader ) ) != sizeof( struct BitMapHeader ) )
  3560.             {
  3561.               error = IFFERR_WRITE;
  3562.               break;
  3563.             }
  3564.  
  3565.             if( error = PopChunk( iff ) )
  3566.               break;
  3567.           }
  3568.  
  3569.           /* write ILBM CMAP (global color map) */
  3570.           if( error = PutILBMCMAP( cb, iff, cregs, numcolors ) )
  3571.             break;
  3572.  
  3573.           /* write ILBM DPAN chunk */
  3574.           {
  3575.             struct DPAnimChunk dpan;
  3576.  
  3577.             dpan . dpan_Version = 0U; /* ??? */
  3578.             dpan . dpan_nframes = numframes;
  3579.             dpan . dpan_FPS     = fps;
  3580.  
  3581.             if( error = PushChunk( iff, 0UL, ID_DPAN, IFFSIZE_UNKNOWN ) )
  3582.               break;
  3583.  
  3584.             if( WriteChunkBytes( iff, (APTR)(&dpan), sizeof( struct DPAnimChunk ) ) != sizeof( struct DPAnimChunk ) )
  3585.             {
  3586.               error = IFFERR_WRITE;
  3587.               break;
  3588.             }
  3589.  
  3590.             if( error = PopChunk( iff ) )
  3591.               break;
  3592.           }
  3593.  
  3594.           /* write ILBM CAMG (amiga view mode) */
  3595.           {
  3596.             if( error = PushChunk( iff, 0UL, ID_CAMG, IFFSIZE_UNKNOWN ) )
  3597.               break;
  3598.  
  3599.             if( WriteChunkBytes( iff, (APTR)(&modeid), sizeof( ULONG ) ) != sizeof( ULONG ) )
  3600.             {
  3601.               error = IFFERR_WRITE;
  3602.               break;
  3603.             }
  3604.  
  3605.             if( error = PopChunk( iff ) )
  3606.               break;
  3607.           }
  3608.  
  3609.           /* Write ILBM BODY (if there is one...) */
  3610.           if( bm )
  3611.           {
  3612.             if( error = PutILBMBody( cb, iff, bm, bmh ) )
  3613.               break;
  3614.  
  3615.             /* Copy current bitmap into both buffers */
  3616.             CopyBitMap( cb, bm, CurrFrame( cb, ac ) );
  3617.             SwapFrames( cb, ac );
  3618.             CopyBitMap( cb, bm, CurrFrame( cb, ac ) );
  3619.           }
  3620.  
  3621.           if( error = PopChunk( iff ) )
  3622.             break;
  3623.         }
  3624.  
  3625.         break; /* end of jump table */
  3626.       }
  3627.  
  3628.       /* All headers written successfully ? */
  3629.       if( error == 0L )
  3630.       {
  3631.         /* Success ! */
  3632.         return( 0L );
  3633.       }
  3634.  
  3635.       CloseIFF( iff );
  3636.     }
  3637.  
  3638.     return( error );
  3639. }
  3640.  
  3641.  
  3642. static
  3643. void EndIFFAnim3( struct ClassBase *cb, struct AnimInstData *aid, struct IFFHandle *iff )
  3644. {
  3645.     if( iff )
  3646.     {
  3647.       LONG error;
  3648.  
  3649.       if( error = PopChunk( iff ) )
  3650.       {
  3651.         error_printf( cb, aid, "error while popping IFF ANIM-3 FORM %ld\n", error );
  3652.       }
  3653.  
  3654.       CloseIFF( iff );
  3655.  
  3656.       verbose_printf( cb, aid, "IFF ANIM-3 sucessfully created\n" );
  3657.     }
  3658. }
  3659.  
  3660.  
  3661. static
  3662. LONG WriteIFFAnim3( struct ClassBase *cb, struct IFFHandle *iff, struct AnimContext *ac, ULONG abstime, ULONG reltime, struct BitMapHeader *bmh, ULONG *cregs, ULONG numcolors, struct BitMap *bm )
  3663. {
  3664.     LONG error = 0L;
  3665.  
  3666.     for( ;; ) /* not a loop, used as a jump-table */
  3667.     {
  3668.       /* write FORM ILBM */
  3669.       {
  3670.         if( error = PushChunk( iff, ID_ILBM, ID_FORM, IFFSIZE_UNKNOWN ) )
  3671.           break;
  3672.  
  3673.         /* write ILBM ANHD (AnimHeader) */
  3674.         {
  3675.           struct AnimHeader animheader = { 0 };
  3676.  
  3677.           animheader . ah_Operation  = acmpShortDelta;
  3678.           animheader . ah_AbsTime    = abstime;
  3679.           animheader . ah_RelTime    = reltime;
  3680.           animheader . ah_Interleave = 2U;
  3681.  
  3682.           if( error = PushChunk( iff, 0UL, ID_ANHD, IFFSIZE_UNKNOWN ) )
  3683.             break;
  3684.  
  3685.           if( WriteChunkBytes( iff, (APTR)(&animheader), sizeof( struct AnimHeader ) ) != sizeof( struct AnimHeader ) )
  3686.           {
  3687.             error = IFFERR_WRITE;
  3688.             break;
  3689.           }
  3690.  
  3691.           if( error = PopChunk( iff ) )
  3692.             break;
  3693.         }
  3694.  
  3695.         /* Palette change ? */
  3696.         if( cregs && numcolors )
  3697.         {
  3698.           if( error = PutILBMCMAP( cb, iff, cregs, numcolors ) )
  3699.             break;
  3700.         }
  3701.  
  3702.         /* Write ANIM-3 delta */
  3703.         if( error = PutAnim3Delta( cb, iff, ac, CurrFrame( cb, ac ), bm ) )
  3704.           break;
  3705.  
  3706.         /* Copy current bitmap into buffer, then swap to next frame */
  3707.         CopyBitMap( cb, bm, CurrFrame( cb, ac ) );
  3708.         SwapFrames( cb, ac );
  3709.  
  3710.         if( error = PopChunk( iff ) )
  3711.           break;
  3712.       }
  3713.  
  3714.       break; /* end of jump-table */
  3715.     }
  3716.  
  3717.     return( error );
  3718. }
  3719.  
  3720.  
  3721. static
  3722. LONG PutAnim3Delta( struct ClassBase *cb, struct IFFHandle *iff, struct AnimContext *ac, struct BitMap *prevbm, struct BitMap *bm )
  3723. {
  3724.     LONG    error;
  3725.     ULONG   len;
  3726.  
  3727.     ULONG  *ptrs = (ULONG *)(ac -> ac_WorkBuffer);
  3728.     WORD   *data = (WORD *)(ptrs + 8UL);  /* data space starts after the 8 byte pointers... */
  3729.     UBYTE   plane;
  3730.     ULONG   planesize = ((bm -> BytesPerRow) * (bm -> Rows)) / sizeof( WORD ); /* size of plane,
  3731.                                                                                 * in compression units (WORD).
  3732.                                                                                 */
  3733.  
  3734.     memset( (ac -> ac_WorkBuffer), 0, (size_t)(ac -> ac_WorkBufferSize) );
  3735.  
  3736.     for( plane = 0U ; plane < (bm -> Depth) ; plane++ )
  3737.     {
  3738.       WORD   distance = 0,
  3739.              i;
  3740.       WORD  *planedata     = (WORD *)(bm -> Planes[ plane ]),
  3741.             *prevplanedata = (WORD *)(prevbm -> Planes[ plane ]);
  3742.  
  3743.       ptrs[ plane ] = (ULONG)((UBYTE *)data - (UBYTE *)(ac -> ac_WorkBuffer));
  3744.  
  3745.       for( i = 0 ; i < planesize ; i++ )
  3746.       {
  3747.         if( (planedata[ i ] != prevplanedata[ i ]) || (distance > 30000) )
  3748.         {
  3749.           if( FALSE /*planedata[ (i + 1) ] != prevplanedata[ (i + 1) ]*/ )
  3750.           {
  3751.             WORD *len;
  3752.  
  3753.             *data++ = -distance - 1;
  3754.             len = data++;
  3755.  
  3756.             *len = 0;
  3757.  
  3758.             while( (planedata[ i ] != prevplanedata[ i ]) && (i < planesize) && (*len < 30000))
  3759.             {
  3760.               *data++ = planedata[ i ];
  3761.               i++;
  3762.               (*len)++;
  3763.             }
  3764.  
  3765.             i--;
  3766.           }
  3767.           else
  3768.           {
  3769.             *data++ = distance;
  3770.             *data++ = planedata[ i ];
  3771.           }
  3772.  
  3773.           distance = 1;
  3774.         }
  3775.         else
  3776.         {
  3777.           distance++;
  3778.         }
  3779.       }
  3780.  
  3781.       /* No changes ? */
  3782.       if( ptrs[ plane ] == (ULONG)((UBYTE *)data - (UBYTE *)(ac -> ac_WorkBuffer)) )
  3783.       {
  3784.         ptrs[ plane ] = 0UL;
  3785.       }
  3786.       else
  3787.       {
  3788.         *data++ = (WORD)0xFFFF; /* terminator */
  3789.       }
  3790.     }
  3791.  
  3792.     if( error = PushChunk( iff, 0UL, ID_DLTA, IFFSIZE_UNKNOWN ) )
  3793.       return( error );
  3794.  
  3795.     len = (ULONG)((UBYTE *)data - (UBYTE *)(ac -> ac_WorkBuffer));
  3796.  
  3797.     if( WriteChunkBytes( iff, (APTR)(ac -> ac_WorkBuffer), len ) != len )
  3798.     {
  3799.       return( IFFERR_WRITE );
  3800.     }
  3801.  
  3802.     error = PopChunk( iff );
  3803.  
  3804.     return( error );
  3805. }
  3806.  
  3807.  
  3808. /*****************************************************************************/
  3809.  
  3810. /* write ILBM CMAP  */
  3811. static
  3812. LONG PutILBMCMAP( struct ClassBase *cb, struct IFFHandle *iff, ULONG *cregs, ULONG numcolors )
  3813. {
  3814.     long                 error;
  3815.     ULONG                i;
  3816.     struct ColorRegister cm;
  3817.  
  3818.     if( error = PushChunk( iff, 0UL, ID_CMAP, IFFSIZE_UNKNOWN ) )
  3819.       return( error );
  3820.  
  3821.     for( i = 0UL ; i < numcolors ; i++ )
  3822.     {
  3823.       /* reduce colors from 32 bits to cmap's 8 bit-per-gun */
  3824.       cm . red   = (UBYTE)(cregs[ ((i * 3) + 0) ] >> 24UL);
  3825.       cm . green = (UBYTE)(cregs[ ((i * 3) + 1) ] >> 24UL);
  3826.       cm . blue  = (UBYTE)(cregs[ ((i * 3) + 2) ] >> 24UL);
  3827.  
  3828.       /* Write R, B, G bytes */
  3829.       if( WriteChunkBytes( iff, (APTR)(&cm), 3UL ) != 3UL )
  3830.       {
  3831.         return( IFFERR_WRITE );
  3832.       }
  3833.     }
  3834.  
  3835.     return( PopChunk( iff ) );
  3836. }
  3837.  
  3838.  
  3839. /*****************************************************************************/
  3840.  
  3841. /* from IFF example code ("iffp/ilbm.h") */
  3842. #define RowBytes( w )     ((((w) + 15) >> 4) << 1)
  3843. #define RowBits( w )      ((((w) + 15) >> 4) << 4)
  3844.  
  3845.  
  3846. static
  3847. LONG PutILBMBody( struct ClassBase *cb, struct IFFHandle *iff, struct BitMap *bitmap, struct BitMapHeader *bmh )
  3848. {
  3849.     LONG     error;
  3850.     LONG     rowBytes        = bitmap -> BytesPerRow;           /* for source modulo only  */
  3851.     LONG     FileRowBytes    = RowBytes( (bmh -> bmh_Width) );  /* width to write in bytes */
  3852.     ULONG    planeCnt        = bmh -> bmh_Depth;                /* number of bit planes including mask */
  3853.     ULONG    iPlane,
  3854.              iRow;
  3855.     BYTE    *planes[ 24 ]; /* array of ptrs to planes & mask */
  3856.  
  3857.     /* Copy the ptrs to bit & mask planes into local array "planes" */
  3858.     for( iPlane = 0 ; iPlane < planeCnt; iPlane++ )
  3859.        planes[ iPlane ] = (BYTE *)(bitmap -> Planes[ iPlane ]);
  3860.  
  3861.     /* Write out a BODY chunk header */
  3862.     if( error = PushChunk( iff, 0L, ID_BODY, IFFSIZE_UNKNOWN ) )
  3863.       return( error );
  3864.  
  3865.     /* Write out the BODY contents */
  3866.     for( iRow = bmh -> bmh_Height ; iRow > 0 ; iRow-- )
  3867.     {
  3868.       for( iPlane = 0 ; iPlane < planeCnt ; iPlane++ )
  3869.       {
  3870.         /* Write next row.*/
  3871.         if( WriteChunkBytes( iff, planes[ iPlane ], FileRowBytes ) != FileRowBytes )
  3872.           return( IFFERR_WRITE );
  3873.  
  3874.         planes[ iPlane ] += rowBytes; /* Possibly skipping unused bytes */
  3875.       }
  3876.     }
  3877.  
  3878.     /* Finish the chunk */
  3879.     error = PopChunk( iff );
  3880.  
  3881.     return( error );
  3882. }
  3883.  
  3884.  
  3885. static
  3886. struct AnimContext *CreateAnimContext( struct ClassBase *cb, ULONG width, ULONG height, ULONG depth )
  3887. {
  3888.     APTR pool;
  3889.  
  3890.     if( pool = CreatePool( (MEMF_PUBLIC | MEMF_CLEAR), 1024UL, 1024UL ) )
  3891.     {
  3892.       struct AnimContext *ac;
  3893.  
  3894.       if( ac = (struct AnimContext *)AllocVecPooled( cb, pool, sizeof( struct AnimContext ) ) )
  3895.       {
  3896.         /* Alloc two bitmaps, used for interleaving */
  3897.         ac -> ac_BitMap[ 0 ] = AllocBitMapPooled( cb, width, height, depth, pool );
  3898.         ac -> ac_BitMap[ 1 ] = AllocBitMapPooled( cb, width, height, depth, pool );
  3899.  
  3900.         /* Alloc work buffer large enougth to hold fancy things... */
  3901.  
  3902.         ac -> ac_WorkBufferSize = (width * height * depth * 2UL) + 1024UL;
  3903.         ac -> ac_WorkBuffer     = (UBYTE *)AllocVecPooled( cb, pool, (ac -> ac_WorkBufferSize) );
  3904.  
  3905.         if( (ac -> ac_BitMap[ 0 ]) && (ac -> ac_BitMap[ 1 ]) && (ac -> ac_WorkBuffer) )
  3906.         {
  3907.           return( ac );
  3908.         }
  3909.       }
  3910.  
  3911.       /* Something goes wrong here, get rid of the resources allocated */
  3912.       DeletePool( pool );
  3913.     }
  3914.  
  3915.     return( NULL );
  3916. }
  3917.  
  3918.  
  3919. #if 0
  3920. static
  3921. struct BitMap *PrevFrame( struct ClassBase *cb, struct AnimContext *ac )
  3922. {
  3923.     if( ac )
  3924.     {
  3925.       return( (ac -> ac_BitMap[ ((ac -> ac_WhichBitMap) ^ 1) ]) );
  3926.     }
  3927.  
  3928.     return( NULL );
  3929. }
  3930. #endif
  3931.  
  3932.  
  3933. static
  3934. void SwapFrames( struct ClassBase *cb, struct AnimContext *ac )
  3935. {
  3936.     if( ac )
  3937.     {
  3938.       ac -> ac_WhichBitMap ^= 1; /* Toggle buffer */
  3939.     }
  3940. }
  3941.  
  3942.  
  3943. static
  3944. struct BitMap *CurrFrame( struct ClassBase *cb, struct AnimContext *ac )
  3945. {
  3946.     if( ac )
  3947.     {
  3948.       return( (ac -> ac_BitMap[ (ac -> ac_WhichBitMap) ]) );
  3949.     }
  3950.  
  3951.     return( NULL );
  3952. }
  3953.  
  3954.  
  3955. static
  3956. void DeleteAnimContext( struct ClassBase *cb, struct AnimContext *ac )
  3957. {
  3958.     if( ac )
  3959.     {
  3960.       DeletePool( (ac -> ac_Pool) );
  3961.     }
  3962. }
  3963.  
  3964.  
  3965.  
  3966.